微信小程序學習筆記(完結)


說明

  1. 本筆記為觀看慕課網微信小程序入門與實戰-全新版尚硅谷2021版微信小程序開發(零基礎小程序開發入門到精通)這兩個教學視頻、並參照 官方的微信開放文檔 記錄整理而成
  2. 兩個教學視頻主要就是是面向初學者的教學視頻,用的原生js進行講解,門檻很低,所以該筆記會將基礎部分也記錄的較為詳細,但有基礎的朋友也可以同時當作梳理基礎知識,學習過程肯定也會更清晰、同時也會有自己不一樣的理解。對於筆記內容有疑問的歡迎提出討論,望求同存異共同進步
  3. 需要預備知識點-->[HTML+CSS+JS基礎]
  4. 本筆記應是小程序詳細學習筆記,主要記錄小程序基礎知識
  5. 部分知識點在官方文檔很詳細(如api部分),最好還是先看官方文檔,本筆記主要就是記錄 學習過程中出現的、需要增加的注解、文檔中沒有的細節、各種知識點的實際用法示例、遇到的問題解決記錄等等等........

目錄

目錄


一、初識微信小程序

1、什么是微信小程序

Ⅰ-小程序歷史

  1. 2017 年度百度百科十大熱詞之一
  2. 微信小程序,簡稱小程序,英文名 Mini Program,是一種不需要下載安裝即可使用的應用 (張小龍對其的定義是無需安裝,用完即走,實際上是需要安裝的,只不過小程序的體積特別小,下載速度很快,用戶感覺不到下載的過程 )
  3. 小程序剛發布的時候要求壓縮包的體積不能大於 1M,,否則無法通過,在2017年4月做了改進,由原來的1M提升到2M;
  4. 2017年1月9日0點,萬眾矚目的微信第一批小程序正式低調上線。

Ⅱ-小程序的優勢

  1. 微信有海量⽤⼾,⽽且粘性很⾼,在微信⾥開發產品更容易觸達⽤⼾;
  2. 推⼴app 或公眾號的成本太⾼。
  3. 開發適配成本低。
  4. 容易⼩規模試錯,然后快速迭代。
  5. 跨平台。

2、小程序准備

Ⅰ-環境准備

  1. 安裝微信小程序開發工具,建議安裝穩定版進行開發

  2. 注冊小程序賬號

  3. 使用注冊的appid進行使用,如果是測試號會限制很多功能

在官網登錄成功后可以看到下面的界面,然后復制你的APPID,悄悄的保存起來,不要給別⼈看到😄。

Ⅱ-新建小程序流程

  1. 打開開發者工具,第一次打開需要掃碼登陸

  2. 新建小程序項目

  1. 填寫項目信息

  1. 新建成功

Ⅲ-微信開發者工具介紹

1)開發工具界面圖解

詳細的使⽤,可以查看官⽹:

2)開發工具的一些基本配置

  1. 點擊工具欄-->詳情-->本地設置,除了默認勾選,需要勾選其他的幾個如:增強編譯、不校驗合法域名...

image-20210420183249939

  1. 常用快捷鍵keyMap修改設置(本人習慣記錄):

    1. ctrl+P:全局搜索

    2. alt+/or shift+j:代碼提示

Ⅳ-微信小程序名稱或者原始id該如何找回?

問題描述:很久沒有進行開發了,小程序的名稱跟原始id都忘記了,找回需要先填寫,如何解決

解決:首先查詢自己的原始id,在這個網站能查詢到自己的原始id,再通過這個原始id進行找回


二、小程序的基本目錄結構與文件作用剖析

小程序框架的⽬標是通過盡可能簡單、⾼效的⽅式讓開發者可以在微信中開發具有原⽣APP體驗的服務。

⼩程序框架提供了⾃⼰的視圖層描述語⾔ WXML 和 WXSS ,以及 JavaScript ,並在視圖層與邏輯層間提供了數據傳輸和事件系統,讓開發者能夠專注於數據與邏輯。

1、小程序文件結構和傳統web對比

傳統web 微信小程序
項目骨架、結構 HTML WXML
頁面樣式 CSS WXSS
項目邏輯 Javascript Javascript
配置 JSON
  1. 通過以上對⽐得出傳統web是三層結構。⽽微信⼩程序是四層結構,多了⼀層配置.json

  2. 當這幾個文件在同一級目錄下且命名相同(后綴不同),可以互相引用卻不用導入

2、基本的項目目錄

Ⅰ-項目目錄解釋

  1. 項目目錄圖解:
  1. app開頭的文件是應用程序級別的文件,更改一處全局生效。而頁面pages的配置優先級高於全局配置(就近原則)
  2. 小程序是允許你修改文件目錄名的

3、小程序配置文件

⼀個⼩程序應⽤程序會包括最基本的兩種配置⽂件。⼀種是全局的app.json 和 ⻚⾯⾃⼰的page.json

Ⅰ-全局配置app.json

  1. app.json 是當前⼩程序的全局配置,包括了⼩程序的所有⻚⾯路徑、界⾯表現、⽹絡超時時間、底部tab等。普通快速啟動項⽬⾥邊的 app.json 配置

  2. 代碼

{
  "pages":[
    "pages/index/index",
    "pages/logs/logs"
 ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
 }
}
  1. 字段的含義

    1)pages 字段⸺⽤於描述當前⼩程序所有⻚⾯路徑,這是為了讓微信客⼾端知道當前你的⼩程序⻚⾯定義在哪個⽬錄。

默認顯示此字段中的第一項

​ 2)window 字段⸺定義⼩程序所有⻚⾯的頂部背景顏⾊,⽂字顏⾊定義等。

​ 3)完整的配置信息請參考 app.json配置

​ 4) tabBar-底部 tab 欄的表現:

更多配置詳細請看app配置文檔

Ⅱ-頁面配置page.json

  1. 這⾥的 page.json 其實⽤來表⽰⻚⾯⽬錄下的 page.json 這類和⼩程序⻚⾯相關的配置。 開發者可以獨⽴定義每個⻚⾯的⼀些屬性,如頂部顏⾊、是否允許下拉刷新等等。 ⻚⾯的配置只能設置 app.json 中部分 window 配置項的內容,⻚⾯中配置項會覆蓋 app.json 的 window 中相同的配置項。

  2. 常用配置屬性列舉:

屬性 類型 默認值 描述
navigationBarBackgroundColor HexColor #000000 導航欄背景顏⾊,如 #000000
navigationBarTextStyle String white 導航欄標題顏⾊,僅⽀持 black / white
navigationBarTitleText String 導航欄標題⽂字內容
backgroundColor HexColor #ffffff 窗⼝的背景⾊
backgroundTextStyle String dark 下拉loading的樣式,僅⽀持 dark / light
enablePullDownRefresh Boolean false 是否全局開啟下拉刷新。 詳⻅ Page.onPullDownRefresh
onReachBottomDistance Number 50 ⻚⾯上拉觸底事件觸發時距⻚⾯底部距離,單位為px。 詳⻅ Page.onReachBottom
disableScroll Boolean false 設置為 true 則⻚⾯整體不能上下滾動;只在⻚⾯配置中有效,⽆法在 app.json 中設置該項

Ⅲ-sitemap 配置-了解即可

⼩程序根⽬錄下的 sitemap.json ⽂件⽤於配置⼩程序及其⻚⾯是否允許被微信索引。主要服務於搜索

4、小程序框架接口

Ⅰ-App(Object object)

  1. 注冊小程序。接受一個 Object 參數,其指定小程序的生命周期回調等。

  2. App() 必須在 app.js 中調用,必須調用且只能調用一次。不然會出現無法預期的后果

  3. 相應的app()參數在下方的小程序生命周期中有指出

AppObject getApp(Object object)

  1. 獲取到小程序全局唯一的 App 實例。

  2. 代碼示例

// other.js
var appInstance = getApp()
console.log(appInstance.globalData) // I am global dat
//或者
const {GbaseUrl} =getApp()  //GbaseUrl是自己在app.js定義的全局變量
  1. Object object
屬性 類型 默認值 必填 說明 最低版本
allowDefault boolean false App 未定義時返回默認實現。當App被調用時,默認實現中定義的屬性會被覆蓋合並到App中。一般用於獨立分包 2.2.4
  1. 注意
  • 不要在定義於 App() 內的函數中,或調用 App 前調用 getApp() 。使用 this 就可以拿到 app 實例。
  • 通過 getApp() 獲取實例之后,不要私自調用生命周期函數

三、小程序的基礎知識儲備

整個小程序學習過程中遇到的 所需基礎知識 或 補充知識 將整合至此

相關知識點本人在一二階段補缺筆記中有記錄,在此便只舉例大概,不詳細記錄

1、Flex 布局

Ⅰ-基本知識點概念

  1. Flex基本概念

    1. Flex 是 Flexible Box 的縮寫,意為”彈性布局”,用來為盒狀模型提供最大的靈活性。

    2. 任何一個容器都可以指定為 Flex 布局。

    3. display: ‘flex’

​ 4) 這部分是一階段基礎知識,可看文檔學習

  1. 在小程序中,通常使用<view/>代替<div/>作為容器來做布局-->代碼示例在第一章的第三小節第三點

Ⅱ-解決flex布局中 space-between方法的排版問題

詳見下方雜記-初學階段遇到的問題與解決-問題Ⅷ

2、移動端相關知識點

自行補充學習,相關知識點本人在一二階段補缺筆記中有記錄,便不再贅述

Ⅰ-物理像素

  1. 屏幕的分辨率

  2. 設備能控制顯示的最小單元,可以把物理像素看成是對應的像素點

Ⅱ-設備獨立像素 、 css 像素

設備獨立像素(也叫密度無關像素),可以認為是計算機坐標系統中的一個點,這個點代表一個可以由程序使用並控制的虛擬像素(比如:CSS 像素,只是在 android 機中 CSS 像素就不叫”CSS 像素”了而是叫”設備獨立像素”),然后由相關系統轉換為物理像素。

Ⅲ-dpr比 、DPI 、PPI

  1. 概念

    1. dpr: 設備像素比,物理像素/設備獨立像素 = dpr, 一般以 Iphon6 的 dpr 為准 dpr = 2

    2. PPI: 一英寸顯示屏上的像素點個數

    3. DPI:最早指的是打印機在單位面積上打印的墨點數,墨點越多越清晰

  2. 不同機型對比表

  1. 部分機型圖示
image-20210508115306709

3、移動端適配方案

相關知識點本人在一二階段補缺筆記中有記錄,想詳細查閱可以去看,這是個面試考點

Ⅰ-viewport 適配

  1. 為什么做 viewport 適配 ?

    a) 手機廠商在生產手機的時候大部分手機默認頁面寬度為 980px

    b) 手機實際視口寬度都要小於 980px,如: iphone6 為 750px

    c) 開發需求需要將 980 的頁面完全顯示在手機屏幕上且沒有滾動條

  2. 代碼實現

<meta name="viewport" content="width=device-width,initial-scale=1.0"> 

Ⅱ- rem 適配

  1. 為什么做 rem 適配?

a) 機型太多,不同的機型屏幕大小不一樣

b) 需求:一套設計稿的內容在不同的機型上呈現的效果一致,根據屏幕大小不同的變化,頁面中的內容也相應變化

  1. 原生代碼實現:
function remRefresh() {
let clientWidth = document.documentElement.clientWidth; 
// 將屏幕等分 10 份
let rem = clientWidth / 10;
document.documentElement.style.fontSize = rem + 'px';
document.body.style.fontSize = '12px';
}
window.addEventListener('pageshow', () => {
remRefresh()
})
// 函數防抖
let timeoutId;
window.addEventListener('resize', () => {
timeoutId && clearTimeout(timeoutId);
timeoutId = setTimeout(() =>{
remRefresh()
}, 300)
})
  1. 第三方庫實現

lib-flexible + px2rem-loader


四、視圖層詳解

框架的視圖層由 WXML 與 WXSS 編寫,由組件來進行展示。

將邏輯層的數據反映成視圖,同時將視圖層的事件發送給邏輯層。

WXML(WeiXin Markup language) 用於描述頁面的結構。

WXS(WeiXin Script) 是小程序的一套腳本語言,結合 WXML,可以構建出頁面的結構。

WXSS(WeiXin Style Sheet) 用於描述頁面的樣式。

組件(Component)是視圖的基本組成單元。

該部分將截取官方文檔並加以注解

1、WXSS樣式文件詳解

  1. WXSS (WeiXin Style Sheets)是一套樣式語言,用於描述 WXML 的組件樣式。

  2. WXSS 用來決定 WXML 的組件應該怎么顯示。

為了適應廣大的前端開發者,WXSS 具有 CSS 大部分特性。同時為了更適合開發微信小程序,WXSS 對 CSS 進行了擴充以及修改。

  1. 與 CSS 相比,WXSS 擴展的特性有:

    1. 響應式⻓度單位:即尺寸單位 -->rpx
    2. 樣式導入
  2. 注意:

當頁面文件在同一級目錄下且命名相同(后綴不同),可以互相引用卻不用導入

Ⅰ-尺寸單位

  1. rpx(responsive pixel): 可以根據屏幕寬度進行自適應。規定屏幕寬為750rpx。如在 iPhone6 上,屏幕寬度為375px,共有750個物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
設備 rpx換算px (屏幕寬度/750) px換算rpx (750/屏幕寬度)
iPhone5 1rpx = 0.42px 1px = 2.34rpx
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx
  1. 建議與注意點:

    1. 開發微信小程序時推薦設計師可以用iPhone6作為視覺稿的標准-->即只有在iPhone6標准中才可以一比二換算,更方便
    2. 在較小的屏幕上不可避免的會有一些毛刺,請在開發時盡量避免這種情況

Ⅱ-樣式導⼊

  1. 使用@import語句可以導入外聯樣式表,也可以和less中的導⼊混⽤,@import后跟需要導入的外聯樣式表的相對路徑(只⽀持相對路徑),用;表示語句結束。
/** common.wxss **/
.small-p {
  padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
  padding:15px;
}

Ⅲ-內聯樣式

框架組件上支持使用 style、class 屬性來控制組件的樣式。

  1. style:靜態的樣式統一寫到 class 中。style 接收動態的樣式,在運行時會進行解析,請盡量避免將靜態的樣式寫進 style 中,以免影響渲染速度
<view style="color:{{color}};" />
  1. class:用於指定樣式規則,其屬性值是樣式規則中類選擇器名(樣式類名)的集合,樣式類名不需要帶上.,樣式類名之間用空格分隔
<view class="normal_view" />

2、WXML語法詳解

WXML(WeiXin Markup Language)是框架設計的⼀套標簽語⾔,結合基礎組件事件系統,可以構建出⻚⾯的結構。

該部分將截取官方文檔加以自己見解說明,同學們也可以直接去看文檔

Ⅰ-數據綁定與寫法規則

  1. WXML 中的動態數據均來自對應 Page 的 data。

  2. Mustache 語法{{}}視作運算標記,里面的內容表示表達式

1) 單向簡單數據綁定

  1. 此處是單向綁定(數據驅動視圖),雙向綁定出現的場景如(input等)將在下方四-3、雙向綁定處記錄

  2. 簡單綁定:數據綁定使用 Mustache 語法(雙大括號)將變量包起來,可以作用於:

//pages.wxml
<view> {{ message }} </view>

// pages.js
Page({
  data: {
    message: 'Hello MINA!'
  }
})
  1. 綁定boolean類型(需要在雙引號之內)

true:boolean 類型的 true,代表真值。false: boolean 類型的 false,代表假值。

<checkbox checked="{{false}}"> </checkbox>

特別注意:不要直接寫 checked="false",其計算結果是一個字符串,轉成 boolean 類型后代表真值

2) 運算

可以在 {{}} 內進行簡單的運算,支持的有如下幾種方式:

  1. 三元運算
<view hidden="{{flag ? true : false}}"> Hidden </view>
  1. 算數運算
<view> {{a + b}} + {{c}} + d </view>
//view中的內容為 `3 + 3 + d`。
//pages.js
Page({
  data: { a: 1, b: 2, c: 3
  }
})
  1. 邏輯判斷
<view wx:if="{{length > 5}}"> </view>
  1. 字符串運算
<view>{{"hello" + name}}</view>
Page({
  data:{name: 'MINA}
})
  1. 數據路徑運算
<view>{{object.key}} {{array[0]}}</view>
//view中的內容為 hello  MINA
Page({
  data: {
    object: {
      key: 'Hello '
    },
    array: ['MINA']
  }
})

3) 組合

也可以在 Mustache 內直接進行組合,構成新的對象或者數組。

  1. 數組 --> 最終組合成數組[0, 1, 2, 3, 4]
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
Page({
  data: { zero: 0 }
})
  1. 對象 -->

    1. 最終組合成的對象是 {for: 1, bar: 2}

      <template is="objectCombine" data="{{for: a, bar: b}}"></template>
      Page({
        data: {a: 1, b: 2}
      })
      
    2. 也可以用擴展運算符 ... 來將一個對象展開-->最終組合成的對象是 {a: 1, b: 2, c: 3, d: 4, e: 5}

      <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
      Page({
        data: {
          obj1: { a: 1, b: 2 },
          obj2: { c: 3, d: 4}
        }
      })
      
    3. 如果對象的 key 和 value 相同,也可以間接地表達。-->最終組合成的對象是 {foo: 'my-foo', bar:'my-bar'}

      <template is="objectCombine" data="{{foo, bar}}"></template>
      Page({
        data: {
          foo: 'my-foo',
          bar: 'my-bar'
        }
      })
      
    4. 注意:上述方式可以隨意組合,但是如有存在變量名相同的情況,后邊的會覆蓋前面 --> 最終組合成的對象是 {a: 5, b: 3, c: 6}

      <template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
      Page({
        data: {
          obj1: { a: 1,  b: 2},
          obj2: { b: 3, c: 4},
          a: 5
        }
      })
      
    5. 注意: 花括號和引號之間如果有空格,將最終被解析成為字符串

        <view wx:for="{{[1,2,3]}} ">
          {{item}}
        </view>
        等同於
                                    
        <view wx:for="{{[1,2,3] + ' '}}">
          {{item}}
        </view>
      

4) 自定義屬性data-*的命名與使用

  1. 同一容器中可以存在多個data-*
  2. 凡是以data-開頭的數據,都會在event的currentTarget中體現,且回缺省data-(data-id --> id)
  3. data-*后面接的單詞將自動轉換 第一個單詞首字母小寫,第二個及之后的單詞首字母大寫 (data-post-my-id --> postMyId)

Ⅱ-列表渲染

1) wx:for

  1. 在組件上使用 wx:for 控制屬性綁定一個數組,即可使用數組中各項的數據重復渲染該組件。

  2. 默認數組的當前項的下標變量名默認為 index,數組當前項的變量名默認為 item

  3. 使用 wx:for-item 可以指定數組當前元素的變量名,使用 wx:for-index 可以指定數組當前下標的變量名:

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>
  1. wx:for 也可以嵌套,下邊是一個九九乘法表
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
    <view wx:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>

2) block wx:for

類似 block wx:if,也可以將 wx:for 用在<block/>標簽上,以渲染一個包含多節點的結構塊。例如:

<block wx:for="{{[1, 2, 3]}}">
 <view> {{index}}: </view>
 <view> {{item}} </view>
</block>

注意: <block/> 並不是一個組件,它僅僅是一個包裝元素,不會在頁面中做任何渲染,只接受控制屬性

3) wx:key

如果列表中項目的位置會動態改變或者有新的項目添加到列表中,並且希望列表中的項目保持自己的特征和狀態(如 input 中的輸入內容,switch 的選中狀態),需要使用 wx:key 來指定列表中項目的唯一的標識符。

wx:key 的值以兩種形式提供
  1. 字符串,代表在for循環的array中item的某個property,該property的值需要是列表中唯一的字符串或數字,且不能動態改變。

  2. 保留關鍵字 *this 代表在 for 循環中的 item 本身,這種表示需要 item 本身是一個唯一的字符串或者數字

<block wx:for="{{posts}}"   wx:key="id"></blocK>
//id是posts數組中的對象里的一個屬性
②使用 wx:key 的意義

當數據改變觸發渲染層重新渲染的時候,會校正帶有 key 的組件,框架會確保他們被重新排序,而不是重新創建,以確保使組件保持自身的狀態,並且提高列表渲染時的效率。

如不提供 wx:key,會報一個 warning, 如果明確知道該列表是靜態,或者不必關注其順序,可以選擇忽略。

4) 列表渲染注意點

① 當 wx:for 的值為字符串時,會將字符串解析成字符串數組
<view wx:for="array">
 {{item}}
</view>
等同於

<view wx:for="{{['a','r','r','a','y']}}">
 {{item}}
</view>
② 花括號和引號之間如果有空格,將最終被解析成為字符串
<view wx:for="{{[1,2,3]}} ">
 {{item}}
</view>
等同於

<view wx:for="{{[1,2,3] + ' '}}" >
 {{item}}
</view>

Ⅲ-條件渲染

1) wx:if

  1. 在框架中,使用 wx:if="" 來判斷是否需要渲染該代碼塊:
<view wx:if="{{condition}}"> True </view>
  1. 也可以用 wx:elifwx:else 來添加一個 else 塊:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

2) block wx:if

因為 wx:if 是一個控制屬性,需要將它添加到一個標簽上。如果要一次性判斷多個組件標簽,可以使用一個 <block/> 標簽將多個組件包裝起來,並在上邊使用 wx:if 控制屬性

<block wx:if="{{true}}">
 <view> view1 </view>
 <view> view2 </view>
</block>

注意: <block/> 並不是一個組件,它僅僅是一個包裝元素,不會在頁面中做任何渲染,只接受控制屬性

3) wx:if vs hidden

  1. 因為 wx:if 之中的模板也可能包含數據綁定,所以當 wx:if 的條件值切換時,框架有一個局部渲染的過程,因為它會確保條件塊在切換時銷毀或重新渲染。

  2. 同時 wx:if 也是惰性的,如果在初始渲染條件為 false,框架什么也不做,在條件第一次變成真的時候才開始局部渲染。

相比之下,hidden 就簡單的多,組件始終會被渲染,只是簡單的控制顯示與隱藏。

  1. 一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運行時條件不大可能改變則 wx:if 較好。

Ⅳ-模板

  1. WXML提供模板(template),可以在模板中定義代碼片段,然后在不同的地方調用

  2. 模板擁有自己的作用域,只能使用 data 傳入的數據以及模板定義文件中定義的 <wxs /> 模塊。

1) 定義模板

使用 name 屬性,作為模板的名字。然后在<template/>內定義代碼片段,如

<!--
 index: int
 msg: string
 time: string
-->
<template name="msgItem">
 <view>
   <text> {{index}}: {{msg}} </text>
   <text> Time: {{time}} </text>
 </view>
</template>

2) 使用模板

  1. 使用 is 屬性,聲明需要的使用的模板,然后將模板所需要的 data 傳入,如:
<template is="msgItem" data="{{...item}}"/>
Page({
  data: {
    item: { index: 0, msg: 'this is a template', time: '2016-09-15'}
  }
})
  1. is 屬性可以使用 Mustache 語法,來動態決定具體需要渲染哪個模板:
<template name="odd">
  <view> odd </view>
</template>
<template name="even">
  <view> even </view>
</template>

<block wx:for="{{[1, 2, 3, 4, 5]}}">
  <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>

Ⅴ-引用

WXML 提供兩種文件引用方式importinclude

1) import

① 使用示例
  1. 在 item.wxml 中定義了一個叫itemtemplate
<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>
  1. 在 index.wxml 中引用了 item.wxml,就可以使用item模板:
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
② import 的作用域

import有作用域的概念,即只會 import 目標文件中定義的 template,而不會import目標文件import的template。

如:C import B,B import A,在C中可以使用B定義的template,在B中可以使用A定義的template,但是C不能使用A定義的template

<!-- A.wxml -->
<template name="A">
 <text> A template </text>
</template>
<!-- B.wxml -->
<import src="a.wxml"/>
<template name="B">
 <text> B template </text>
</template>
<!-- C.wxml -->
<import src="b.wxml"/>
<template is="A"/>  <!-- Error! Can not use tempalte when not import A. -->
<template is="B"/>

2) include

include 可以將目標文件除了 <template/> <wxs/> 外的整個代碼引入,相當於是拷貝到 include 位置,如:

<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>

3、雙向綁定

Ⅰ-雙向綁定語法

Ⅱ- setData-->數據更新

  1. setData 是小程序開發中使用最頻繁的接口,也是最容易引發性能問題的接口。

  2. 小程序的視圖層目前使用 WebView 作為渲染載體,而邏輯層是由獨立的 JavascriptCore 作為運行環境。在架構上,WebView 和 JavascriptCore 都是獨立的模塊,並不具備數據直接共享的通道。當前,視圖層和邏輯層的數據傳輸,實際上通過兩邊提供的 evaluateJavascript 所實現。即用戶傳輸的數據,①需要將其轉換為字符串形式傳遞,② 同時把轉換后的數據內容拼接成一份 JS 腳本,③再通過執行 JS 腳本的形式傳遞到兩邊獨立環境

  3. evaluateJavascript 的執行會受很多方面的影響,數據到達視圖層並不是實時的

1) 簡單使用

setData可以直接將數據加入data中;如果在data中已經有該值,則修改它有着創建+更新功能 但正常是用來更新

Page({
   data: {posts: [],test: "測試數據",flag: true},
   //更新
	this.setData({posts: content})
})

2) 常見的 setData 操作錯誤

頻繁的去 setData

在我們分析過的一些案例里,部分小程序會非常頻繁(毫秒級)的去setData,其導致了兩個后果:

  • Android 下用戶在滑動時會感覺到卡頓,操作反饋延遲嚴重,因為 JS 線程一直在編譯執行渲染,未能及時將用戶操作事件傳遞到邏輯層,邏輯層亦無法及時將操作處理結果及時傳遞到視圖層;
  • 渲染有出現延時,由於 WebView 的 JS 線程一直處於忙碌狀態,邏輯層到頁面層的通信耗時上升,視圖層收到的數據消息時距離發出時間已經過去了幾百毫秒,渲染的結果並不實時;
每次 setData 都傳遞大量新數據

setData的底層實現可知,我們的數據傳輸實際是一次 evaluateJavascript 腳本過程,當數據量過大時會增加腳本的編譯執行時間,占用 WebView JS 線程,

后台態頁面進行 setData

當頁面進入后台態(用戶不可見),不應該繼續去進行setData,后台態頁面的渲染用戶是無法感受的,另外后台態頁面去setData也會搶占前台頁面的執行

4、事件系統

Ⅰ-什么是事件?

  • 事件是視圖層到邏輯層的通訊方式
  • 事件可以將用戶的行為反饋到邏輯層進行處理。
  • 事件可以綁定在組件上,當達到觸發事件,就會執行邏輯層中對應的事件處理函數。
  • 事件對象可以攜帶額外信息,如 id, dataset, touches。

Ⅱ-事件分類

事件分為冒泡事件和非冒泡事件:

  1. 冒泡事件:當一個組件上的事件被觸發后,該事件會向父節點傳遞。

  2. 非冒泡事件:當一個組件上的事件被觸發后,該事件不會向父節點傳遞。

  3. WXML的冒泡事件列表:

類型 觸發條件 最低版本
touchstart 手指觸摸動作開始
touchmove 手指觸摸后移動
touchcancel 手指觸摸動作被打斷,如來電提醒,彈窗
touchend 手指觸摸動作結束
tap 手指觸摸后馬上離開
longpress 手指觸摸后,超過350ms再離開,如果指定了事件回調函數並觸發了這個事件,tap事件將不被觸發 1.5.0
longtap 手指觸摸后,超過350ms再離開(推薦使用longpress事件代替)
transitionend 會在 WXSS transition 或 wx.createAnimation 動畫結束后觸發
animationstart 會在一個 WXSS animation 動畫開始時觸發
animationiteration 會在一個 WXSS animation 一次迭代結束時觸發
animationend 會在一個 WXSS animation 動畫完成時觸發
touchforcechange 在支持 3D Touch 的 iPhone 設備,重按時會觸發 1.9.90
  1. :除上表之外的其他組件自定義事件如無特殊聲明都是非冒泡事件,如 formsubmit事件,inputinput事件,scroll-viewscroll事件,(詳見各個組件)

Ⅲ-事件的綁定方式

1) 普通事件綁定-bind 綁定

  1. 代碼示例
<view bindtap="tapName" class='start_container'>
//也可以加冒號分隔
	//<view bind:tap="tapName" class='start_container'>
<text class='start'>開啟小程序之旅</text>
</view>
Page({
  tapName: function(event) { console.log(event)}
})
  1. 如果用戶點擊這個 view ,則頁面的 tapName 會被調用。

  2. 此時,頁面的 this.data.tapName 必須是一個字符串,指定事件處理函數名;如果它是個空字符串,則這個綁定會失效(可以利用這個特性來暫時禁用一些事件)

  3. 自基礎庫版本 1.5.0 起,在大多數組件和自定義組件中, bind 后可以緊跟一個冒號,其含義不變,如 bind:tap 。基礎庫版本 2.8.1 起,在所有組件中開始提供這個支持。

2) 綁定並阻止事件冒泡-catch 綁定:

  1. bind 外,也可以用 catch 來綁定事件。與 bind 不同, catch 會阻止事件向上冒泡。

  2. 代碼示例:

<view id="outer" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3">
      inner view
    </view>
  </view>
</view>
  1. 例如在上邊這個例子中,點擊 inner view 會先后調用handleTap3handleTap2(因為tap事件會冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父節點傳遞),點擊 middle view 會觸發handleTap2,點擊 outer view 會觸發handleTap1

3) 互斥事件綁定

  1. 自基礎庫版本 2.8.2 起,除 bindcatch 外,還可以使用 mut-bind 來綁定事件。一個 mut-bind 觸發后,如果事件冒泡到其他節點上,其他節點上的 mut-bind 綁定函數不會被觸發,但 bind 綁定函數和 catch 綁定函數依舊會被觸發。

  2. 換而言之,所有 mut-bind 是“互斥”的,只會有其中一個綁定函數被觸發。同時,它完全不影響 bindcatch 的綁定效果

  3. 例如在下邊這個例子中,點擊 inner view 會先后調用 handleTap3handleTap2 ,點擊 middle view 會調用 handleTap2handleTap1

<view id="outer" mut-bind:tap="handleTap1">
  outer view
  <view id="middle" bindtap="handleTap2">
    middle view
    <view id="inner" mut-bind:tap="handleTap3">
      inner view
    </view>
  </view>
</view>

Ⅳ-事件的捕獲階段

  1. 自基礎庫版本 1.5.0 起,觸摸類事件支持捕獲階段。捕獲階段位於冒泡階段之前,且在捕獲階段中,事件到達節點的順序與冒泡階段恰好相反。需要在捕獲階段監聽事件時,可以采用capture-bindcapture-catch關鍵字,后者將中斷捕獲階段和取消冒泡階段。

  2. 在下面的代碼中,點擊 inner view 會先后調用handleTap2handleTap4handleTap3handleTap1

<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
  outer view
  <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
    inner view
  </view>
</view>

如果將上面代碼中的第一個capture-bind改為capture-catch,將只觸發handleTap2

<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
  outer view
  <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
    inner view
  </view>
</view>

Ⅴ-事件對象

如無特殊說明,當組件觸發事件時,邏輯層綁定該事件的處理函數會收到一個事件對象。

1) BaseEvent 基礎事件對象屬性列表

  1. 表格:
屬性 類型 說明 基礎庫版本
type String 代表事件的類型
timeStamp Integer 事件生成時的時間戳--頁面打開到觸發事件所經過的毫秒數
target Object 觸發事件的組件的一些屬性值集合--觸發事件的源組件
currentTarget Object 當前組件的一些屬性值集合--事件綁定的當前組件
mark Object 事件標記數據 2.7.1
  1. 補充說明

  2. target

    屬性 類型 說明
    id String 事件源組件的id
    dataset Object 事件源組件上由data-開頭的自定義屬性組成的集合
  3. currentTarget

    屬性 類型 說明
    id String 當前組件的id
    dataset Object 當前組件上由data-開頭的自定義屬性組成的集合

    說明: target 和 currentTarget 可以參考上例中,點擊 inner view 時,handleTap3 收到的事件對象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件對象 target 就是 inner,currentTarget 就是 middle

2) TouchEvent 觸摸事件對象屬性列表(繼承 BaseEvent):

  1. 表格:
屬性 類型 說明
touches Array 觸摸事件,當前停留在屏幕中的觸摸點信息的數組
changedTouches Array 觸摸事件,當前變化的觸摸點信息的數組
  1. 補充說明

  2. touches

    touches 是一個數組,每個元素為一個 Touch 對象(canvas 觸摸事件中攜帶的 touches 是 CanvasTouch 數組)。 表示當前停留在屏幕上的觸摸點。

    屬性 類型 說明
    identifier Number 觸摸點的標識符
    pageX, pageY Number 距離文檔左上角的距離,文檔的左上角為原點 ,橫向為X軸,縱向為Y軸
    clientX, clientY Number 距離頁面可顯示區域(屏幕除去導航條)左上角距離,橫向為X軸,縱向為Y軸
  3. changedTouches

    changedTouches 數據格式同 touches。 表示有變化的觸摸點,如從無變有(touchstart),位置變化(touchmove),從有變無(touchend、touchcancel)

3) CustomEvent 自定義事件對象屬性列表(繼承 BaseEvent):

  1. 表格
屬性 類型 說明
detail Object 額外的信息
自定義事件所攜帶的數據,如表單組件的提交事件會攜帶用戶的輸入,媒體的錯誤事件會攜帶錯誤信息,詳見組件定義中各個事件的定義。

五、邏輯層詳解

  1. 原理:小程序開發框架的邏輯層使用 JavaScript 引擎為小程序提供開發者 JavaScript 代碼的運行環境以及微信小程序的特有功能。

​ 邏輯層將數據進行處理后發送給視圖層,同時接受視圖層的事件反饋。

​ 開發者寫的所有代碼最終將會打包成一份 JavaScript 文件,並在小程序啟動的時候運行,直到小程序銷毀。這一行為類似ServiceWorker,所以邏輯層也稱之為 App Service。

  1. JavaScript 的基礎上,我們增加了一些功能,以方便小程序的開發:
  • 增加 AppPage 方法,進行程序注冊頁面注冊
  • 增加 getAppgetCurrentPages 方法,分別用來獲取 App 實例和當前頁面棧。
  • 提供豐富的 API,如微信用戶數據,掃一掃,支付等微信特有能力。
  • 提供模塊化能力,每個頁面有獨立的作用域

注意:小程序框架的邏輯層並非運行在瀏覽器中,因此 JavaScript 在 web 中一些能力都無法使用,如 windowdocument 等。

該部分將截取官方文檔並加以注解

1、頁面路由

在小程序中所有頁面的路由全部由框架進行管理

Ⅰ-頁面棧與路由方式

  1. 框架以的形式維護了當前的所有頁面。
  2. 對於路由的觸發方式以及頁面生命周期函數如下:
路由方式 頁面棧表現 觸發時機 路由前頁面 路由后頁面
初始化 新頁面入棧 小程序打開的第一個頁面 onLoad, onShow
打開新頁面 新頁面入棧 調用 API wx.navigateTo
使用組件
onHide onLoad, onShow
頁面重定向 當前頁面出棧,新頁面入棧 調用 API wx.redirectTo
使用組件
onUnload onLoad, onShow
頁面返回 頁面不斷出棧,直到目標返回頁 調用 API wx.navigateBack
使用組件
用戶按左上角返回按鈕
onUnload onShow
Tab 切換 頁面全部出棧,只留下新的 Tab 頁面
如果從沒有tabBar的頁面跳轉至有tabBar的頁面就一定要用這個,而不是上面的,否則會報錯
調用 API wx.switchTab
使用組件
用戶切換 Tab
各種情況請參考下表
重啟動 頁面全部出棧,只留下新的頁面 調用 API wx.reLaunch
使用組件
onUnload onLoad, onShow
  1. 代碼示例:
wx.navigateTo({ //當前頁面被隱藏,緩存在棧中,最多存放10個頁面
url: "/pages/posts/post" //跳轉的頁面路徑
})
 wx.redirectTo({ //當前頁面被銷毀
url: "/pages/posts/post"
})
  1. Tab 切換對應的生命周期(以 A、B 頁面為 Tabbar 頁面,C 是從 A 頁面打開的頁面,D 頁面是從 C 頁面打開的頁面為例):
當前頁面 路由后頁面 觸發的生命周期(按順序)
A A Nothing happend
A B A.onHide(), B.onLoad(), B.onShow()
A B(再次打開) A.onHide(), B.onShow()
C A C.onUnload(), A.onShow()
C B C.onUnload(), B.onLoad(), B.onShow()
D B D.onUnload(), C.onUnload(), B.onLoad(), B.onShow()
D(從轉發進入) A D.onUnload(), A.onLoad(), A.onShow()
D(從轉發進入) B D.onUnload(), B.onLoad(), B.onShow()

Ⅱ-Tips

  • navigateTo, redirectTo 只能打開非 tabBar 頁面。
  • switchTab 只能打開 tabBar 頁面。
  • reLaunch 可以打開任意頁面。
  • 頁面底部的 tabBar 由頁面決定,即只要是定義為 tabBar 的頁面,底部都有 tabBar。
  • 調用頁面路由帶的參數可以在目標頁面的onLoad中獲取。
  • 注意:開發者可以使用 getCurrentPages() 函數獲取當前頁面棧
  • 頁面棧中最多存在10

2、模塊化

可以將一些公共的代碼抽離成為一個單獨的 js 文件,作為一個模塊。模塊只有通過 module.exports 或者 exports 才能對外暴露接口。


六、組件與組件庫

1、官方組件

重點舉例⼩程序中常⽤的布局組件 view,tex 等,現只舉例部分,之后遇到覺得需要mark再寫入,大部分可以看官方文檔組件部分,便不太多贅述

Ⅰ-view

  1. 在小程序中,通常使用<view/>代替<div/>作為容器來做布局
<!--pages/welcome/welcome.wxml-->
<view class="container">
  <image class="avatar" src="/images/測試頭像圖片.jpg"></image>
  <text>Hello,洪jl</text>
  <!-- <button>開啟小程序之旅</button> -->
  <view>
    <text>開啟小程序之旅</text>
  </view>
</view>

Ⅱ-text

  1. ⽂本標簽

  2. 只能嵌套text

  3. ⻓按⽂字可以復制(只有該標簽有這個功能)-->selectable

  4. 可以對如: 空格回車&nbsp; 進⾏編碼 -->decode

屬性名 類型 默認值 說明
selectable Boolean false ⽂本是否可選
decode Boolean false 是否解碼
<text selectable="{{false}}" decode="{{false}}">
   普&nbsp;通
 </text>

Ⅲ-image

  1. 圖⽚標簽,image組件默認寬度320px、⾼度240px,所以如果不進行寬高設置,不會進行自適應

  2. ⽀持懶加載

屬性名 類型 默認值 說明
src String 圖⽚資源地址
mode String scaleToFill 圖⽚裁剪、縮放的模式
lazy-load Boolean false 圖⽚懶加載
  1. mode模式列舉:
模式 說明
縮放 scaleToFill 不保持縱橫⽐縮放圖⽚,使圖⽚的寬⾼完全拉伸⾄填滿image 元素
縮放 aspectFit 保持縱橫⽐縮放圖⽚,使圖⽚的⻓邊能完全顯⽰出來。
縮放 aspectFill 保持縱橫⽐縮放圖⽚,只保證圖⽚的短邊能完全顯⽰出來
縮放 widthFix 寬度不變,⾼度⾃動變化,保持原圖寬⾼⽐不變
裁剪 top 不縮放圖⽚,只顯⽰圖⽚的頂部區域
裁剪 bottom 不縮放圖⽚,只顯⽰圖⽚的底部區域
裁剪 center 不縮放圖⽚,只顯⽰圖⽚的中間區域
裁剪 left 不縮放圖⽚,只顯⽰圖⽚的左邊區域
裁剪 right 不縮放圖⽚,只顯⽰圖⽚的右邊區域
裁剪 top lefttop right
bottom leftbottom right
不縮放圖⽚,只顯示值所指向區域
  1. 代碼示例:
 <image class="avatar"  mode="aspectFit" src="/images/測試頭像圖片.jpg"></image>
  1. 應用場景舉例,簡單效果對比

    1. 使用默認mode效果 -->會將圖片進行拉伸,導致圖片變形

    2. 設置為aspectFill效果 -->保持縱橫⽐縮放圖⽚,只保證圖⽚的短邊能完全顯⽰出來,圖片不會變形

    3. 根據不同的場景選擇不同的mode才是最正確的,就如同該截圖場景中,aspectFill明顯優於默認

Ⅳ-swiper

滑塊視圖容器。其中只可放置swiper-item組件,否則會導致未定義的行為。

  1. 代碼示例
<!--pages/posts/posts.wxml-->
<view>
  <!-- 
    //1. "false" ==true 普通字符串  
    //    "{{false}}"==false   {{}}視作運算標記,里面的內容表示表達式 
    //2. 當你的屬性為true時,可以省略value值-- indicator-dots="{{true}}" == indicator-dots
  -->
  <swiper indicator-dots="{{true}}" autoplay interval="2000" duration="1000" vertical circular>
    <swiper-item>
      <!-- 插槽 -->
      <image mode="scaleToFill" src="/images/1.jpg"></image>
    </swiper-item>
    <swiper-item>
      <!-- 插槽 -->
      <image mode="scaleToFill" src="/images/2.jpg"></image>
    </swiper-item>
    <swiper-item>
      <!-- 插槽 -->
      <image mode="scaleToFill" src="/images/3.jpg"></image>
    </swiper-item>
  </swiper>
</view>
  1. 該輪播圖代碼效果預覽:

Ⅴ-scroll-view

可滾動視圖區域。使用豎向滾動時,需要給scroll-view一個固定高度,通過 WXSS 設置 height。組件屬性的長度單位默認為px,2.4.0起支持傳入單位(rpx/px)。

  1. 使用舉例圖

2、LinUi組件庫

Ⅰ-安裝與使用

  1. Lin UI 是基於 微信小程序原生語法 實現的組件庫。遵循簡潔,易用的設計規范。

  2. 與其他組件庫不同的是,除了提供基本的組件外,還會提供 wxs模塊高級組件電商組件模塊 等等。 例如,在電商項目里常用的 SKU聯動選擇城市選擇器

  3. 安裝過程可看官方文檔:

  1. 打開小程序的項目根目錄,執行下面的命令(如果使用了雲開發,需要進入miniprogram文件夾下執行下面的命令)
npm init
/*注意事項
1.執行npm init進行初始化,此時會生成一個package.json文件,如果不進行npm init,在構建npm的時候會報一個錯誤:沒有找到 node_modules 目錄
2.不建議使用cnpm,這樣會帶來一些未知的錯誤。如果網絡情況不佳,可以使用下面的命令行更換為淘寶源。
npm config set registry https://registry.npm.taobao.org */

2)繼續執行下面的命令

npm install lin-ui
  1. 安裝完成后在小程序需要點擊工具-->構建 npm才可以使用(所有npm引入的都需要這一步)
  2. 要使用自定義組件的話,需要在配置.json文件中(可以在全局的也可以在頁面的,作用域不同)注冊,具體實現看下面示例

Ⅱ-avatar頭像

  1. 要使用自定義組件的話,需要在當前page頁面.json文件中注冊
//page.json
{
  "usingComponents": {
    "l-avatar":"/miniprogram_npm/lin-ui/avatar/index",
     "組件名(可以自取,一般如果是linui,就l-xxx)":"構建后的路徑--要具體到那個文件夾下的js"
  }
}
  1. 使用:
<!--pages/welcome/welcome.wxml-->
<view class="container">
  <!-- <image class="avatar" lazy-load="true" mode="aspectFit" src="/images/測試頭像圖片.jpg"></image> -->
 <l-avatar 
 class="l-avatar"
 placement="bottom" 
 open-data="{{['userAvatarUrl','userNickName']}}"
 size="200"
 />
</view>

/* pages/welcome/welcome.wxss */
//可以自己寫樣式類,加到組件上
.l-avatar{
  margin-top: 160rpx;
}

Ⅲ-icon

  1. 在當前page頁面.json文件中注冊
{
  "usingComponents": {
    "l-icon":"/miniprogram_npm/lin-ui/icon/index"
  }
}
  1. 使用
 <l-icon size="20" color="#34bfa3" name="cart"></l-icon>
 <l-icon name="research"></l-icon>

七、小程序API

1、數據緩存

類似於網頁的localStorage

官方文檔很詳細,此處給出具體地址,翻閱文檔即可

2、交互

一些微信官方給出的組件,具體參數解釋看文檔,以下給出學習過程中代碼示例

Ⅰ-wx.showToast與wx.showModal

  1. wx.showToast代碼示例:
  wx.showToast({
      //此處其實已經被修改完狀態,才開始提示,所以要反過來
      title: this.data.collected ? '收藏成功' : '取消收藏',
      duration: 1000
   })
  1. wx.showModal代碼示例:
  async onCollect(e) {
    const result = await wx.showModal({
      title:  !this.data.collected ? '進行收藏' : '取消收藏',
    })
    if (!result.confirm) return; //點擊取消退出
     .......//點擊確認后運行的代碼
      wx.showToast({
      //此處其實已經被修改完狀態,才開始提示,所以要反過來
      title: this.data.collected ? '收藏成功' : '取消收藏',
      duration: 1000
    })
  },
  1. 運行效果示例(兩者並存的效果):

3、媒體

Ⅰ-媒體音樂播放

  1. wx.getBackgroundAudioManager--播放音樂

  2. 代碼示例

const app = getApp() //此處keyi 
onLoad: function (options) {
  const mgr = wx.getBackgroundAudioManager()
    this.data._mgr = mgr
    // if(app.gIsPlayMusic) {  此處進入即默認播放
    //   mgr.src = this.data.postData.music.url
    //   mgr.title = this.data.postData.music.title
    // }

    mgr.onPlay(() => {
      console.log("監聽播放")
    })
    mgr.onPause(() => {
      console.log("監聽暫停")
    })
    }
/**
   * 音樂播放
   */
  onMusic() {
    const mgr = this.data._mgr
    if (this.data.isPlaying) {
      mgr.pause()
      app.gIsPlayMusicId = -1
    } //當前播放狀態如果為true則終止(stop())、pause()暫停
    else {
      mgr.src = this.data.postData.music.url  //此處為播放
      mgr.title = this.data.postData.music.title
      app.gIsPlayMusicId = this.data._pid
    }

    this.setData({
      isPlaying: !this.data.isPlaying
    })
  },

Ⅱ-圖片

1) wx.previewImage(Object object)

在新頁面中全屏預覽圖片。預覽的過程中用戶可以進行保存圖片、發送給朋友等操作

  1. 代碼示例

    <!--pages/movie-detail/movie-detail.wxml-->
    <image catch:tap="onViewPost" class="movie-img" src="{{movie.images}}"></image>
    // pages/movie-detail/movie-detail.js
    onViewPost(e) { //相冊功能(預覽)
        wx.previewImage({
          urls: [images1,images2],
        })
     },
    
  2. 詳見開發文檔

4、界面

Ⅰ-Tab Bar

使用時在app.json中進行配置即可,相關配置詳情看全局配置文檔,如果需要進行相應操作看官方文檔

"tabBar": {
   "selectedColor": "#333333",
   "color": "#999999",
   "borderStyle": "black",
   "position": "top",
   "list": [
     {
       "pagePath": "pages/posts/posts",
       "text": "閱讀",
       "iconPath": "/images/tabBar/yuedu.png",
       "selectedIconPath": "/images/tabBar/yuedu_1.png"
     },
     {
       "pagePath": "pages/movies/movies",
       "text": "電影",
       "iconPath": "/images/tabBar/dianying_1.png",
       "selectedIconPath": "/images/tabBar/dianying.png"
     }
   ]
 }

八、小程序生命周期

分為應⽤⽣命周期⻚⾯⽣命周期

關於小程序前后台的定義和小程序的運行機制,請參考運行機制章節。

1、應用生命周期

  1. 應用生命周期表
屬性 類型 必填 說明 場景 最低版本
onLaunch function 生命周期回調——監聽小程序初始化。 小程序初始化完成時觸發,全局只觸發一次。參數也可以使用 wx.getLaunchOptionsSync 獲取。
onShow function 生命周期回調——監聽小程序啟動或切前台。 小程序啟動,或從后台進入前台顯示時觸發。也可以使用 wx.onAppShow 綁定監聽
onHide function 生命周期回調——監聽小程序切后台。 小程序從前台進入后台時觸發。也可以使用 wx.onAppHide 綁定監聽
onError function 錯誤監聽函數。 小程序發生腳本錯誤或 API 調用報錯時觸發。也可以使用 wx.onError 綁定監聽
onPageNotFound function 頁面不存在監聽函數。 小程序要打開的頁面不存在時觸發。也可以使用 wx.onPageNotFound 綁定監聽。 1.9.90
onUnhandledRejection function 未處理的 Promise 拒絕事件監聽函數。 小程序有未處理的 Promise 拒絕時觸發。也可以使用 wx.onUnhandledRejection 綁定監聽 2.10.0
onThemeChange function 監聽系統主題變化 系統切換主題時觸發。也可以使用 wx.onThemeChange 綁定監聽 2.11.0
其他 any 開發者可以添加任意的函數或數據變量到 Object 參數中,用 this 可以訪問
  1. 代碼示例:
App({
  onLaunch (options) {
    // Do something initial when launch.
  },
  onShow (options) {
    // Do something when show.
  },
  onHide () {
    // Do something when hide.
  },
  onError (msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
  ,
  onPageNotFound(res) {
 	 wx.redirectTo({
   	 url: 'pages/...'
 	 }) // 如果是 tabbar 頁面,請使用 wx.switchTab
  }
    
})

2、頁面生命周期

  1. 頁面生命周期表
屬性 類型 說明
data Object 頁面的初始數據
options Object 頁面的組件選項,同 Component 構造器 中的 options ,需要基礎庫版本 2.10.1
onLoad function 生命周期回調—監聽頁面加載
onShow function 生命周期回調—監聽頁面顯示
onReady function 生命周期回調—監聽頁面初次渲染完成
onHide function 生命周期回調—監聽頁面隱藏
onUnload function 生命周期回調—監聽頁面卸載
onPullDownRefresh function 監聽用戶下拉動作
onReachBottom function 頁面上拉觸底事件的處理函數
onShareAppMessage function 用戶點擊右上角轉發
onShareTimeline function 用戶點擊右上角轉發到朋友圈
onAddToFavorites function 用戶點擊右上角收藏
onPageScroll function 頁面滾動觸發事件的處理函數
onResize function 頁面尺寸改變時觸發,詳見 響應顯示區域變化
onTabItemTap function 當前是 tab 頁時,點擊 tab 時觸發
其他 any 開發者可以添加任意的函數或數據到 Object 參數中,在頁面的函數中用 this 可以訪
  1. 官方的小程序頁面生命周期圖:
image-20210425142044724

3、組件生命周期-不算在小程序生命周期中

組件的生命周期,指的是組件自身的一些函數,這些函數在特殊的時間點或遇到一些特殊的框架事件時被自動觸發


九、自定義組件

開發者可以將頁面內的功能模塊抽象成自定義組件,以便在不同的頁面中重復使用;也可以將復雜的頁面拆分成多個低耦合的模塊,有助於代碼維護。自定義組件在使用時與基礎組件非常相似

這部分將截取文檔自定義組件部分中常見的部分進行注解

1、組件模板和樣式

類似於頁面,自定義組件擁有自己的 wxml 模板和 wxss 樣式。

Ⅰ-組件樣式

組件對應 wxss 文件的樣式,只對組件wxml內的節點生效。編寫組件樣式時,需要注意以下幾點:

  • 組件和引用組件的頁面不能使用id選擇器(#a)、屬性選擇器([a])和標簽名選擇器,請改用class選擇器。

  • 組件和引用組件的頁面中使用后代選擇器(.a .b)在一些極端情況下會有非預期的表現,如遇,請避免使用。

  • 子元素選擇器(.a>.b)只能用於 view 組件與其子節點之間,用於其他組件可能導致非預期的情況。

  • 繼承樣式,如 fontcolor ,會從組件外繼承到組件內。

  • 除繼承樣式外, app.wxss 中的樣式、組件所在頁面的的樣式對自定義組件無效(除非更改組件樣式隔離選項)。

#a { } /* 在組件中不能使用 */
[a] { } /* 在組件中不能使用 */
button { } /* 在組件中不能使用 */
.a > .b { } /* 除非 .a 是 view 組件節點,否則不一定會生效 */

除此以外,組件可以指定它所在節點的默認樣式,使用 :host 選擇器(需要包含基礎庫 1.7.2 或更高版本的開發者工具支持)。

注:此處本人出了一個問題,詳見--->本筆記的雜記->初學者階段遇到的問題與解決->Ⅶ

Ⅱ-外部樣式類

  1. 有時,組件希望接受外部傳入的樣式類。此時可以在 Component 中用 externalClasses 定義段定義若干個外部樣式類。這個特性可以用於實現類似於 view 組件的 hover-class 屬性:頁面可以提供一個樣式類,賦予 viewhover-class ,這個樣式類本身寫在頁面中而非 view 組件的實現中。

注意:在同一個節點上使用普通樣式類和外部樣式類時,兩個類的優先級是未定義的,因此最好避免這種情況。

  1. 代碼示例:

    1. 自定義組件部分定義與占位符示例

      /* 組件 custom-component.js */
      Component({
        externalClasses: ['my-class']
      })
                                                                           
      <!-- 組件 custom-component.wxml 如何引用 -->
      <custom-component class="my-class">這段文本的顏色由組件外的 class 決定</custom-component>                                 
      

      這樣,組件的使用者可以指定這個樣式類對應的 class ,就像使用普通屬性一樣。在 2.7.1 之后,可以指定多個對應的 class 。

  2. 外部使用自定義組件並傳入樣式類

    <!-- 頁面的 WXML -->
    <custom-component my-class="red-text" />
    <custom-component my-class="large-text" />
    <!-- 以下寫法需要基礎庫版本 2.7.1 以上  注意 這只是一個組件傳入兩個類名,而不是分別創建兩個組件-->
    <custom-component my-class="red-text large-text" />
                                                                                                                       
    ------------ 樣式類聲明 頁面.wxss ---------------------------------
    .red-text {
      color: red;
    }
    .large-text {
      font-size: 1.5em;
    }
    
  3. 主要用途:

    1. 如果子組件都是我們自己開發的,而且無所謂改動自定義組件源碼,那可以不使用這個

    2. 如果自定義組件封裝已經足夠成熟,不想再動其中樣式源碼,就可以用外部樣式類進行對自定義組件樣式改變(使用!important屬性能將樣式優先級提高),以此進行對於封裝好的組件的樣式修改,同理可以運用於第三方庫

      .movielist{ //外部樣式類
        margin-bottom: 25rpx;
        background-color: #fff !important;  //此處就可以將這個樣式提升到自定義組件樣式優先級之上
      }
      
  4. 以后如果自己封裝自定義組件,就可以向外暴露外部樣式類

2、組件間通信與事件

Ⅰ-組件間通信

組件間的基本通信方式有以下幾種。

  • WXML 數據綁定:用於父組件向子組件的指定屬性設置數據,僅能設置 JSON 兼容數據(自基礎庫版本 2.0.9 開始,還可以在數據中包含函數)。具體在 組件模板和樣式 章節中介紹。
  • 事件:用於子組件向父組件傳遞數據,可以傳遞任意數據。
  • 如果以上兩種方式不足以滿足需要,父組件還可以通過 this.selectComponent 方法獲取子組件實例對象,這樣就可以直接訪問組件的任意數據和方法。

Ⅱ-觸發事件

自定義組件觸發事件時,需要使用 triggerEvent 方法,指定事件名、detail對象和事件選項

  1. 官方代碼示例
<!-- 在自定義組件中 -->
<button bindtap="onTap">點擊這個按鈕將觸發“myevent”事件</button>
//js文件中
Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail對象,提供給事件監聽函數
      var myEventOption = {} // 觸發事件的選項
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})
  1. 本人在hello小程序源碼中應用
<!--pages/posts/posts.wxml-->
<block wx:for="{{posts}}" wx:for-item="item" wx:key="postId" wx:for-index="index">
    <post bind:posttap="onGoDetail" res="{{item}}" />
  </block>
// components/posts/index.js  這是自定義組件

 methods: {
    onTap (e) {  //此處不能用箭頭函數,否則`  this.triggerEvent`將會找不到報錯
    const pid = this.data.res.postId
    // console.log( this.data)
    // console.log( this.properties)
      this.triggerEvent('posttap',{
        pid   //這個參數會在事件調用處獲取到
      })
    },
 }

// pages/posts/posts.js  這個是在調用自定義組件的頁面的js中,即可以使用自己的方法,單純是調用自定義組件定義的事件
  onGoDetail: (e) => { //獲取組件的自定義屬性
    //先判斷,如果e.currentTarget.dataset去得到值,就取有值的 下面這3種寫法效果等同
    //  let pid = (e.currentTarget.dataset.id)?e.currentTarget.dataset.id:e.detail.pid 
    // let pid = e.detail.pid|e.currentTarget.dataset.id  
    let pid = e.detail.pid || e.currentTarget.dataset.id
    wx.navigateTo({
      url: '/pages/post-detail/post-detail?pid=' + pid,
  })

雜記

體系學習過程筆記外的知識點

1、微信開發者工具使用技巧

Ⅰ-新建頁面的技巧與規則:

  1. 本技巧適用於微信開發者工具
  2. 當你需要新建一個頁面時:新建一個page文件目錄-->右鍵新建page-->輸入page名字-->一次生成所需四個文件 且自動注冊到app.json
  3. 如果配置文件中出現錯誤時,自動新建無法成功,更無法自動注冊

Ⅱ-指定初始頁面

當你寫多個page時,如果每次通過修改app.json的配置項來指定初始頁面,十分麻煩

  1. 可以在app.json用"entryPagePath":"pages/頁面文件夾/頁面文件名" 配置首頁,但仍要修改配置文件,十分麻煩

  2. 使用編譯器的工具欄-->添加編譯模式進行指定初始化頁面(啟動頁面默認值要先刪除才有提示)

image-20210421181759900
  1. 添加后每次調試只要選擇編譯模式,就可以切換初始頁面

Ⅲ-ctrl+滾輪縮放工具界面

只能調成字體了,這個BUG被修復了🐶

2、微信開發常見編程方法與細節

學習、練習、開發微信小程序過程中遇到的一些基礎知識與細節記錄

Ⅰ-相對路徑規則:

  1. /代表根目錄:如引入根目錄下的images/圖片

    <image src="/images/測試頭像圖片.jpg"></image>
    
  2. 其余的如:../上一級目錄、./同級目錄,都與一般無異

Ⅱ-npm引入第三方庫后需進行構建

安裝第三方庫后在小程序需要點擊工具-->構建 npm才可以使用

所有npm引入的都需要這一步

3、初學階段遇到的問題與解決

這部分將記錄本人初學小程序過程遇到的問題,這部分應該大部分是小程序初學者才會遇到的,或者是本人雖然可以直接解決但覺得別人可能會遇到的便記錄下來。而后續進階階段或者實戰開發時遇到的問題,將記錄在下面另一章節

Ⅰ-設置整個page的背景色

  1. 問題:當我設置頁面背景色時,發現添加背景色的page的高度是被內容撐起而不是全屏?如何解決最簡單
    問題截圖image-20210421153332813解決后<img https://img2022.cnblogs.com/blog/1987782/202203/1987782-20220316132901761-166859934.png微信小程序學習筆記中的圖片/image-20210421153607334.png" alt="image-20210421153607334" style="zoom: 50%;" />

    解決:可以在你需要修改的page的樣式文件中,給<page/>標簽加樣式,默認小程序是使用 作為最外層的

    page{
      background-color: #b3d4db;
    }
    

Ⅱ-小程序中使用less

原⽣⼩程序不⽀持 less ,其他基於⼩程序的框架⼤體都⽀持,如 wepy , mpvue , taro 等。 但是僅僅因為⼀個less功能,⽽去引⼊⼀個框架,肯定是不可取的。因此可以⽤以下⽅式來實現

  1. 編輯器是vscode

  2. 安裝插件easy less

  1. 在vscode的設置中加⼊如下,配置
  "less.compile": {
        "outExt": ".wxss"
   }
  1. 在要編寫樣式的地⽅,新建 less ⽂件,如 index.less ,然后正常編輯即可。

Ⅲ-報錯: TypeError: wx.getMenuButtonBoundingClientRect is not a function

控制台報錯: TypeError: wx.getMenuButtonBoundingClientRect is not a function

問題分析:這個 api是 更高版本版本支持的,你的用戶有的客戶端基礎庫版本 小於這個基礎庫。你在小程序后台設置下 最低基礎庫2.1.0.那樣用戶客戶端基礎庫版本低於此就會提示升級

解決:image-20210421172805580

Ⅳ-警告:無效的page.json

這是初學者才會犯下的錯誤,但也記錄下來

  1. 問題:在page.json配置文件中與要修改導航欄顏色,卻發生報錯
    image-20210422094205182
  2. 解決:修改相應報錯配置(翻閱文檔),雖然響應的屬性值相同,但一個外層包裹window,另一個沒有包裹
    image-20210422094901528

Ⅴ-報錯:typeError: Cannot read property 'mark' of undefined

  1. 報錯

image-20210426170705465

  1. 解決:最終發現是小程序工具設置問題

需要勾選增強編譯

Ⅵ-微信小程序中使用箭頭函數導致this指向錯誤的問題

  1. 問題代碼截圖:
image-20210427161221380
  1. 問題分析:

眾所周知,箭頭函數會改變this指向,當我使用箭頭函數后,函數中的this不再指向實例而是指向函數本身,導致data其實是找不到的發生報錯

  1. 問題解決:

    1. 不使用箭頭函數:

         async onCollect(e) {
            const result = await wx.showModal({
              title:  !this.data.collected ? '進行收藏' : '取消收藏',
            })
            if (!result.confirm) return;
      
            let postCollected = this.data._postCollected //將當前data中(相當於之前本地緩存的postCollected)拉去下來,防止被覆蓋
            postCollected[this.data._pid] = !this.data.collected
            this.setData({
              collected: !this.data.collected
            })
            wx.setStorageSync('posts_collected', postCollected)
            wx.showToast({
              //此處其實已經被修改完狀態,才開始提示,所以要反過來
              title: this.data.collected ? '收藏成功' : '取消收藏',
              duration: 1000
            })
          },
      
    2. 使用箭頭函數,但需要保存this指向

        let con  //用來保存this指向
                                                                                          
        Page({
          //1. 生命周期函數中保存this指向
        onLoad: function (options) {
            	con=this  //用來保存this指向
        },
          //2. 函數體寫法
        onCollect:async (e)=> {  箭頭函數寫法,需要保存this指向
           console.log(con)
          const result = await wx.showModal({
            title:  !con.data.collected ? '進行收藏' : '取消收藏',
          })
          if (!result.confirm) return;
                                                                                          
          let postCollected = con.data._postCollected //將當前data中(相當於之前本地緩存的postCollected)拉去下來,防止被覆蓋
          postCollected[con.data._pid] = !con.data.collected
          con.setData({
            collected: !con.data.collected
          })
          wx.setStorageSync('posts_collected', postCollected)
          wx.showToast({
            //此處其實已經被修改完狀態,才開始提示,所以要反過來
            title: con.data.collected ? '收藏成功' : '取消收藏',
            duration: 1000
          })
        })
      

Ⅶ-警告: Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors

  1. 出現場景:在我將之前寫好的樣式模塊抽出成自定義組件時,控制台突然出現警告

  1. 分析:我使用了屬性選擇器,而官方文檔在自定義組件部分有要求不能使用,防止出現樣式錯誤,
image-20210430101700628
  1. 解決:將屬性選擇器刪除即可

Ⅷ-解決flex布局中 space-between方法的排版問題

flex布局 justify-content:space-between; 解決最后一排數量不夠自動向兩端排列問題

  1. 問題圖示:
image-20210507095120687
  1. 分析:flex 布局兩端對齊當最后一排數量不夠時,會出現以下布局情況

  1. 解決方法1:父級添加after偽類法
image-20210507095349825

ps:這種解決方案只適合每列有3個的分布情況,如果布局每列有4個,5個,就需要解決方法2

  1. 解決方法2:使用grid柵格布局,此處不詳解,只將解決方案指出,有需要的直接百度搜索使用grid柵格布局即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM