在原生小程式中,元件之間是如何通訊的?

語言: CN / TW / HK
ead>

highlight: an-old-hope

2. 元件的建立和引用

2.1 建立自定義元件
  1. 建立元件

    • 在專案的根目錄中,滑鼠右鍵,建立 components -> test 資料夾
    • 在新建的 components -> test 資料夾上,滑鼠右鍵,點選 新建 Component
    • 鍵入元件的名稱之後回車,會自動生成元件對應的 4 個檔案,字尾名分別為 .js.json.wxml.wxss
    • 注意:為了保證目錄結構的清晰,建議把不同的元件,存放到單獨目錄中

2.2 區域性引用元件
  1. 元件的引用方式

    • 元件的引用方式分為 區域性引用全域性引用

      • 區域性引用:元件只能在當前被引用的頁面內使用
      • 全域性引用:元件可以在每個小程式頁面中使用
  2. 區域性引用元件

    • 頁面的 .json 配置檔案中引用元件的方式,叫做 區域性引用

2.3 全域性引入元件

app.json 全域性配置檔案中引用元件的方式,叫做 全域性引用

2.5 全域性引用和區域性引用的區別
  1. 根據元件的使用頻率範圍,來選擇合適的引用方式:

    • 如果某元件在多個頁面中經常被用到,建議進行 全域性引用
    • 如果某元件只在特定的頁面中被用到,建議進行 區域性引用
2.6 元件和頁面的區別
  1. 從表面來看,元件和頁面都是由 .js.json.wxml.wxss 這四個檔案組成的。但是,元件和 頁面的 .js.json 檔案有明顯的不同:

    • 元件的 .json 檔案中需要宣告 "component": true 屬性

    • 元件的 .js 檔案中呼叫的是 Component() 函式

      • 整個程式啟動呼叫的是 App()
      • 某個頁面的渲染呼叫的是 Page()
      • 某個元件的渲染呼叫的是 Component()
    • 元件的事件處理函式需要定義到 methods 節點中

    3. 元件的資料、方法和屬性

3.1 定義 data 私有資料
  1. 在小程式元件中,用於元件模板渲染的私有資料,需要定義到 data 節點中

3.2 methods 方法
  1. 在小程式元件中,事件處理函式和自定義方法需要定義到 methods 節點中

3.3 定義 properties 屬性
  1. 在小程式元件中, properties 是元件的對外屬性,用來接收外界(父元件)傳遞到元件中的資料

3.4 data 和 properties 的區別
  1. 在小程式的元件中, properties 屬性和 data 資料的用法相同,它們都是可讀可寫的,只不過:

    • data 更傾向於儲存元件的私有資料
    • properties 更傾向於儲存外界傳遞到元件中的資料
    • 所以, 也不太建議修改 properties 資料,如果要修改 properties 的資料, 最好通過子元件通訊給父元件的方式實現

3.5 使用 setData 修改 properties 的值
  1. 由於 data 資料和 properties 屬性在本質上沒有任何區別,因此 properties 屬性的值也可以用於頁面渲染,或使用 setDataproperties 中的屬性重新賦值

4. 資料監聽器

4.1 什麼是資料監聽器以及其基礎語法
  1. 什麼是資料監聽器

    資料監聽器用於監聽和響應任何屬性和資料欄位的變化,從而執行特定的操作。它的作用類似於 vue 中的 watch 偵聽器。在小程式元件中,資料監聽器的基本語法格式如下

4.2 資料監聽器的基本用法
  1. 元件結構

  2. 元件的 js 程式碼

  1. 完整程式碼

    html <view> {{ num1 }} + {{ num2 }} = {{ sum }} </view> ​ <button type="warn" bindtap="addNum1">Num + 1</button> <button type="warn" bindtap="addNum2">Num + 2</button> ​

    js // components/test/test.js Component({ ​ /** * 元件的初始資料 */ data: { num1: 0, num2: 0, sum: 0 }, ​ // 資料偵聽器 observers: { 'num1, num2': function (newNum1, newNum2) { this.setData({ sum: newNum1 + newNum2 }) } }, ​ /** * 元件的方法列表 */ methods: { addNum1 () { this.setData({ num1: this.data.num1 + 1 }) }, ​ addNum2 () { this.setData({ num2: this.data.num2 + 1 }) } } }) ​

4.3 監聽物件屬性的變化
  1. 資料監聽器支援監聽物件中單個或多個屬性的變化

html <button type="warn" bindtap="changeObj">監聽物件的屬性</button> ​ <view>{{ obj.name }}</view>

js // components/test/test.js Component({ // 元件的初始資料 data: { obj: { name: 'tom' } }, ​ // 資料偵聽器 observers: { 'obj.name': function (newName) { console.log(newName) } }, ​ // 方法列表 methods: { changeObj() { this.setData({ 'obj.name': 'jerry' }) } } }) ​

5. 元件的生命週期

5.1 元件全部的生命週期函式

| 生命週期 | 引數 | 描述 | | ---------- | -------------- | -------------------- | | created | | 在元件例項剛剛被建立時執行 | | attached | | 在元件例項進入頁面節點樹時執行 | | ready | 無 | 在元件在檢視層佈局完成後執行 | | moved | 無 | 在元件例項被移動到節點樹另一個位置時執行 | | detached | 無 | 在元件例項被從頁面節點樹移除時執行 | | error | Object Error | 每當元件方法丟擲錯誤時執行 |

5.2 元件主要的生命週期函式

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

  1. 最重要的生命週期是 created, attached, detached ,包含一個元件例項生命流程的最主要時間點。

    • 元件例項剛剛被建立好時, created 生命週期被觸發

      • 此時還不能呼叫 setData
      • 通常情況下,這個生命週期只應該用於給元件 this 新增一些自定義屬性欄位
    • 在元件完全初始化完畢、進入頁面節點樹後, attached 生命週期被觸發

      • this.data 已被初始化完畢
      • 這個生命週期很有用,絕大多數初始化工作可以在這個時機進行
    • 在元件離開頁面節點樹後, detached 生命週期被觸發

      • 退出一個頁面時,會觸發頁面內每個自定義元件的detached 生命週期被觸發
      • 如果元件還在頁面節點樹中,則 detached 會被觸發。
      • 此時適合做一些清理性質的工作
5.3 lifetime 節點
  1. 生命週期方法可以直接定義在 Component 構造器的第一級引數中,元件的的生命週期也可以在 lifetimes 欄位內進行宣告(這是推薦的方式,其優先順序最高)

js //推薦方式 lifetimes: { attached () { console.log('在元件例項進入頁面節點樹') }, detached () { console.log('在元件例項被從頁面節點樹移除') } }, ​ //以下是舊方式 attached () { console.log('~~~~~在元件例項進入頁面節點樹') }, detached () { console.log('~~~~~在元件例項被從頁面節點樹移除') }, ​ /** * 元件的初始資料 */ data: { // rgb 的顏色值物件 _rgb: { r: 0, g: 0, b: 0 }, // 根據 rgb 物件的三個屬性,動態計算 fullColor 的值 fullColor: '0, 0, 0' }

6. 元件所在頁面的生命週期

6.1 什麼是元件所在頁面的生命週期
  1. 有時,自定義元件的行為依賴於頁面狀態的變化,此時就需要用到元件所在頁面的生命週期

    • 例如:每當觸發頁面的 show 生命週期函式的時候,我們希望能夠重新生成一個隨機的 RGB 顏色值。在自定義元件中,元件所在頁面的生命週期函式有如下 3 個,分別是

| 生命週期 | 引數 | 描述 | | ------ | ------------- | -------------- | | show | 無 | 元件所在的頁面被展示時執行 | | hide | 無 | 元件所在的頁面被隱藏時執行 | | resize | Object Size | 元件所在的頁面尺寸變化時執行 |

6.2 pageLifetimes 節點
  1. 元件所在頁面的生命週期函式,需要定義在 pageLifetimes 節點中

6.3 生成隨機的 RGB 顏色值

js Component({ // 在元件的methods節點中,定義一個隨機顏色的方法 methods: { _randomColor() { // 設定data中的資料 this.setData({ _rgb: { r: Math.floor(Math.random() * 256), g: Math.floor(Math.random() * 256), b: Math.floor(Math.random() * 256) } }) } }, // 在元件內部的pageLifetimes節點中,監聽元件在頁面的生命週期函式 pageLifetimes: { // 在頁面被展示的時候,呼叫該方法 show() { this._randomColor() }, hide() { }, // 頁面被隱藏 resize() { } // 頁面尺寸變化 } })


7. 插槽

7.1 什麼是插槽
  1. 在自定義元件的 wxml 結構中,可以提供一個 節點(插槽),用於承載元件使用者提供的 wxml 結構

  1. 其實插槽, 說的通俗一些, 就是 子元件挖坑,父元件填坑 的過程。由父元件在使用子元件的時候, 決定子元件內部的某一些佈局展示

    • 子元件通過挖坑
    • 父元件通過元件標籤中間的內容來填坑
7.2 單個插槽
  1. 在小程式中,預設每個自定義元件中只允許使用一個 slot 佔位,這種個數上的限制叫做單個插槽

    • 預設情況下,一個元件的 wxml 中只能有一個 slot
    • 需要使用多 slot 時,可以在元件 js 中宣告啟用
    • 注意:小程式中目前只有預設插槽和多個插槽,暫不支援作用域插槽

7.3 啟動多個插槽

在小程式的自定義元件中,需要使用多 插槽時,可以在元件的 .js 檔案中

7.4 定義多個插槽

可以在元件的 .wxml 中使用多個 標籤,以不同的 name 來區分不同的插槽

8. 父子元件通訊

8.1 瞭解父子元件之間通訊的 3 個方式
  1. 屬性繫結

    • 用於父元件向子元件的指定屬性設定資料,僅能設定 JSON 相容的資料(只能傳遞資料,不能傳遞方法)
  2. 事件繫結

    • 用於子元件向父元件傳遞資料,可以傳遞任意資料(包括陣列和方法)
  3. 獲取元件例項

    • 父元件還可以通過 this.selectComponent() 獲取子元件例項物件這樣就可以直接訪問子元件的任意資料和方法
8.2 屬性繫結
  1. 傳遞資料

    • 屬性繫結用於實現父向子傳值,而且只能傳遞普通型別的資料,無法將方法傳遞給子元件

  1. 接收資料

    • 子元件在 properties 節點中宣告對應的屬性並使用

8.3 實現子元件的 count 屬性自增 + 1

js data: { count: 0 }

js addCount() { this.setData({ count: this.data.count + 1 }) }

8.4 瞭解事件繫結的 4 個核心實現步驟
  1. 事件繫結用於實現子向父傳值,可以傳遞任何型別的資料。使用步驟如下:

    • 父元件js 中,定義一個函式,這個函式即將通過自定義事件的形式,傳遞給子元件
    • 父元件wxml 中,通過自定義事件的形式,將步驟 1 中定義的函式引用,傳遞給子元件
    • 子元件js 中,通過呼叫 this.triggerEvent('自定義事件名稱', {/* 引數物件 */}),將資料傳送到父元件
    • 在父元件的 js 中,通過 e.detail 獲取到子元件傳遞過來的資料
8.5 瞭解事件繫結的核心實現程式碼
  1. 步驟 1: 在父元件的 js 中,定義一個函式,這個函式即將通過自定義事件的形式,傳遞給子元件

  2. 步驟 2:在父元件的 wxml 中,通過自定義事件的形式,將 步驟 1 中定義的函式引用,傳遞給子元件

  3. 步驟 3:在 子元件js 中,通過呼叫 this.triggerEvent('自定義事件名稱', {/* 引數物件 */}),將資料傳送到父元件

  4. 步驟 4:在父元件的 js 中,通過 e.detail 獲取到子元件傳遞過來的資料

8.6 使用 selectComponent 獲取元件例項

可在父元件裡呼叫 this.selectComponent("id或class選擇器"),獲取子元件的例項物件,從而直接訪問子元件的任意資料和方法。呼叫時需要傳入一個選擇器,例如 this.selectComponent(".my-component")

9. 使用 npm

9.1 小程式對 npm 的支援和限制

目前,小程式中已經支援使用 npm 安裝第三方包,從而來提高小程式的開發效率。但是,在小程式中使用 npm 包有如下 3 個限制:

  1. 不支援依賴於 Node.js 內建庫的包

    • 不支援依賴於 Node 核心模組的包
    • fs Node 檔案系統模組 -- 不支援
    • path Node 路徑模組 -- 不支援
  2. 不支援依賴於瀏覽器內建物件的包

    • 小程式的宿主環境是微信,不存在 DOM 和 DOM
    • 所以依賴於內建物件的包,也不能夠使用
  3. 不支援依賴於 C++ 外掛的包

總結:雖然 npm 上的包有千千萬,但是能供小程式使用的包卻“為數不多”

9.2 瞭解什麼是 vant Weapp
  1. Vant有贊前端團隊開源的移動端元件庫,於 2016 年開源,已持續維護 4 年時間。Vant 對內承載了有贊所有核心業務,對外服務十多萬開發者,是業界主流的移動端元件庫之一
  2. 採用 MIT 開源許可協議,對商業使用比較友好
  3. 掃描下方小程式二維碼,體驗元件庫示例

9.3 安裝 Vant 元件庫

在小程式專案中,安裝 Vant 元件庫主要分為如下幾步

  1. 通過 npm 安裝

    • 注意:專案目錄不能存在中文!不能存在中文!不能存在中文!否則會報錯 !

shell npm init -y

shell npm i @vant/[email protected] -S --production

  1. 構建 npm 包功能

    如果提示構建失敗,可以將微信開發者工具重啟,重啟以後,執行小程式專案,檢視是否還報錯

    • 建議先點選 微信開發者工具 --> 詳情 --> 本地設定 --> 使用 npm 模組

    • 然後點選 微信開發者工具 --> 選單欄 --> 工具 --> 構建npm

    • 提示 構建成功,耗時 xxx 秒 且控制檯沒有任何的錯誤,說明包構建成功,可以進行使用

      • 否則就需要把 node_modulesminiprogram_npm 刪除
      • 刪除以後,重新安裝包,並點選 工具 --> 構建npm,進行重新構建
  2. 修改 app.json

    • styles: v2 進行移除,防止 小程式本身的 UI 樣式和 Vant 的元件樣式庫 衝突

詳細的操作地址:安裝 vant Weapp

9.4 使用 Vant 元件

安裝完 Vant 元件庫之後,可以在 app.jsonusingComponents 節點中引入需要的元件,即可在 wxml 中直接使用元件

josn "usingComponents": { "van-button": "@vant/weapp/button/index" }

html <van-button type="default">預設按鈕</van-button> <van-button type="primary">主要按鈕</van-button> <van-button type="info">資訊按鈕</van-button> <van-button type="warning">警告按鈕</van-button> <van-button type="danger">危險按鈕</van-button>

9.5 定義和使用 CSS 變數 (瞭解)

Vant Weapp 使用 CSS 變數來實現定製主題。 關於 CSS 變數的基本用法,請參考 MDN 文件

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties

  1. 自定義屬性(有時候也被稱作 CSS變數 或者 級聯變數)是由 CSS 作者定義的,它包含的值可以在整個文件中重複使用

  2. 由自定義屬性標記設定值

    • 宣告一個自定義屬性,屬性名需要以兩個減號(--)開始,屬性值則可以是任何有效的 CSS
    • 比如: --main-color: black;
  3. var() 函式來獲取值

    • color: var(--main-color);

```html

CSS 變數

​ ```

9.6 使用 CSS 變數定製 Vant 的主題樣式 (瞭解)

app.wxss 中,寫入 CSS 變數,即可對全域性生效

所有可用的顏色變數,請參考 Vant 官方提供的配置檔案

https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less

9.7 什麼是小程式 API 的 Promise 化
  1. 基於回撥函式的非同步 API 的缺點

    • 預設情況下,小程式官方提供的非同步 API 都是基於回撥函式實現的,例如,網路請求的 API 需要按照如下的方式呼叫

    • 這種程式碼的缺點是顯而易見的, 容易造成回撥地獄的問題,程式碼的可讀性、維護性差!而我們就想將這種型別的程式碼使用 API Promise 化進行改造

  2. 什麼是 API Promise

    • API Promise 化,指的是通過額外的配置,將官方提供的、基於回撥函式的非同步 API ,升級改造為基於 Promise 的非同步 API ,從而提高程式碼的可讀性、維護性,避免回撥地獄的問題
9.8 安裝並構建 miniprogram-api-promise
  1. 在小程式中,實現 API Promise 化主要依賴於 miniprogram-api-promise 這個第三方的 npm

    js npm i --save [email protected]

  2. 下載完成,我們不能直接使用這個包,而是需要再次重新構建npm包

    • 建議在構建前先刪除原有的 miniprogram_npm
    • 然後再點選工具,構建 npm
  1. 如果刪除了 miniprogram_npm 目錄,構建還是失敗

    • 需要把 node_modulesminiprogram_npm 刪除
    • 刪除以後,重新安裝包,重新安裝以後,再次進行構建
9.9 三個步驟實現 API 的 Promise 化

  1. 在小程式入口檔案中呼叫一次 promisifyAll()方法

    js import { promisifyAll } from 'miniprogram-api-promise'

  2. 宣告一個常量,為一個空物件

    js const wxp = wx.p = {}

  3. 呼叫 promisifyAll()方法

    js promisifyAll(wx, wxp)

  4. 上述程式碼是什麼含義呢 ?

    • promisifyAll : 做的事就是將 wx 擁有的屬性方法都 copy 並改造了一份給了 wxp 這個物件
    • 然而, wxp 只是當前 js 檔案的一個常量,只能在當前檔案使用
    • 因此:我們在 wx 上掛載一個屬性 p 讓他和 wxp 指向同一個空物件
    • 在其他頁面或者元件就可以通過全域性物件 wx 點出 p 來訪問到 wxp
    • 此時 wx.p 發起非同步的請求時,得到的是一個 promise 物件
    • 那麼我們就可以使用 async/await 簡化 Promise 語法

js // 1、匯入 promisifyAll 這個方法 import { promisifyAll } from 'miniprogram-api-promise' ​ // 2、宣告一個空物件 wxp // wxp 只是一個單純的變數,只能夠在當前 js 中使用,外部不能使用 // wx 是微信小程式最頂級的物件 // 只需要往 wx 上去掛載一個物件即可 // 掛載好,以後 wxp 和 wx.p 指定的是同一個記憶體空間 // 也就是說 wxp 拷貝得到的 wx 的屬性和方法 // wx.p 同樣也是擁有的 // 呼叫方式: wx.p.xxxxx 即 wx.p.request({}) const wxp = wx.p = {} ​ // 3、promisifyAll 作用就是將 wx 內部的方法和屬性深拷貝一份給 wxp 這個物件 promisifyAll(wx, wxp) ​

9.10 呼叫 Promise 化之後的非同步 API

html <van-button type="warning" bindtap="getInfo">警告按鈕</van-button>

js async getInfo () { const { data: res } = await wx.p.request({ url: 'https://www.escook.cn/api/get', method: 'GET', data: { name: 'zs', age: 19 } }) ​ console.log(res) }