在原生小程序中,組件之間是如何通信的?
ead>highlight: an-old-hope
2. 組件的創建和引用
2.1 創建自定義組件
-
創建組件
- 在項目的根目錄中,鼠標右鍵,創建
components
->test
文件夾 - 在新建的
components
->test
文件夾上,鼠標右鍵,點擊新建 Component
- 鍵入組件的名稱之後回車,會自動生成組件對應的 4 個文件,後綴名分別為
.js
,.json
,.wxml
和.wxss
- 注意:為了保證目錄結構的清晰,建議把不同的組件,存放到單獨目錄中
- 在項目的根目錄中,鼠標右鍵,創建
2.2 局部引用組件
-
組件的引用方式
-
組件的引用方式分為
局部引用
和全局引用
局部引用
:組件只能在當前被引用的頁面內使用全局引用
:組件可以在每個小程序頁面中使用
-
-
局部引用組件
- 在
頁面的 .json
配置文件中引用組件的方式,叫做局部引用
- 在
2.3 全局引入組件
在 app.json
全局配置文件中引用組件的方式,叫做 全局引用
2.5 全局引用和局部引用的區別
-
根據組件的
使用頻率
和範圍
,來選擇合適的引用方式:- 如果某組件
在多個頁面中經常被用到
,建議進行全局引用
- 如果某組件只
在特定的頁面中被用到
,建議進行局部引用
- 如果某組件
2.6 組件和頁面的區別
-
從表面來看,組件和頁面都是由
.js
、.json
、.wxml
和.wxss
這四個文件組成的。但是,組件和 頁面的.js
與.json
文件有明顯的不同:-
組件的 .json 文件中需要聲明
"component": true
屬性 -
組件的 .js 文件中調用的是
Component()
函數- 整個程序啟動調用的是
App()
- 某個頁面的渲染調用的是
Page()
- 某個組件的渲染調用的是
Component()
- 整個程序啟動調用的是
-
組件的事件處理函數需要定義到
methods
節點中
3. 組件的數據、方法和屬性
-
3.1 定義 data 私有數據
-
在小程序組件中,用於組件模板渲染的私有數據,需要定義到
data
節點中
3.2 methods 方法
-
在小程序組件中,事件處理函數和自定義方法需要定義到
methods
節點中
3.3 定義 properties 屬性
-
在小程序組件中,
properties
是組件的對外屬性,用來接收外界(父組件)傳遞到組件中的數據
3.4 data 和 properties 的區別
-
在小程序的組件中,
properties
屬性和data
數據的用法相同,它們都是可讀可寫的,只不過:data
更傾向於存儲組件的私有數據properties
更傾向於存儲外界傳遞到組件中的數據- 所以, 也不太建議修改
properties
數據,如果要修改properties
的數據, 最好通過子組件通信給父組件的方式實現
3.5 使用 setData 修改 properties 的值
- 由於
data
數據和properties
屬性在本質上沒有任何區別,因此properties
屬性的值也可以用於頁面渲染,或使用setData
為properties
中的屬性重新賦值
4. 數據監聽器
4.1 什麼是數據監聽器以及其基礎語法
-
什麼是數據監聽器
數據監聽器用於監聽和響應任何屬性和數據字段的變化,從而執行特定的操作。它的作用類似於
vue
中的watch
偵聽器。在小程序組件中,數據監聽器的基本語法格式如下
4.2 數據監聽器的基本用法
-
組件結構
-
組件的
js
代碼
-
完整代碼
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 監聽對象屬性的變化
-
數據監聽器支持監聽對象中單個或多個屬性的變化
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 組件主要的生命週期函數
組件的生命週期,指的是組件自身的一些函數,這些函數在特殊的時間點或遇到一些特殊的框架事件時被自動觸發。
-
最重要的生命週期是
created
,attached
,detached
,包含一個組件實例生命流程的最主要時間點。-
組件實例剛剛被創建好時,
created
生命週期被觸發- 此時還不能調用
setData
- 通常情況下,這個生命週期只應該用於給組件 this 添加一些自定義屬性字段
- 此時還不能調用
-
在組件完全初始化完畢、進入頁面節點樹後,
attached
生命週期被觸發this.data
已被初始化完畢- 這個生命週期很有用,絕大多數初始化工作可以在這個時機進行
-
在組件離開頁面節點樹後,
detached
生命週期被觸發- 退出一個頁面時,會觸發頁面內每個自定義組件的
detached
生命週期被觸發 - 如果組件還在頁面節點樹中,則
detached
會被觸發。 - 此時適合做一些清理性質的工作
- 退出一個頁面時,會觸發頁面內每個自定義組件的
-
5.3 lifetime 節點
- 生命週期方法可以直接定義在
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 什麼是組件所在頁面的生命週期
-
有時,自定義組件的行為依賴於頁面狀態的變化,此時就需要用到組件所在頁面的生命週期
- 例如:每當觸發頁面的
show
生命週期函數的時候,我們希望能夠重新生成一個隨機的RGB
顏色值。在自定義組件中,組件所在頁面的生命週期函數有如下 3 個,分別是
- 例如:每當觸發頁面的
| 生命週期 | 參數 | 描述 |
| ------ | ------------- | -------------- |
| show | 無 | 組件所在的頁面被展示時執行 |
| hide | 無 | 組件所在的頁面被隱藏時執行 |
| resize | Object Size
| 組件所在的頁面尺寸變化時執行 |
6.2 pageLifetimes 節點
-
組件所在頁面的生命週期函數,需要定義在
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 什麼是插槽
- 在自定義組件的
wxml
結構中,可以提供一個 節點(插槽),用於承載組件使用者提供的wxml
結構
-
其實插槽, 説的通俗一些, 就是
子組件挖坑,父組件填坑
的過程。由父組件在使用子組件的時候, 決定子組件內部的某一些佈局展示- 子組件通過挖坑
- 父組件通過組件標籤中間的內容來填坑
7.2 單個插槽
-
在小程序中,默認每個自定義組件中只允許使用一個
slot
佔位,這種個數上的限制叫做單個插槽- 默認情況下,一個組件的
wxml
中只能有一個slot
- 需要使用多
slot
時,可以在組件js
中聲明啟用 - 注意:小程序中目前只有默認插槽和多個插槽,暫不支持作用域插槽
- 默認情況下,一個組件的
7.3 啟動多個插槽
在小程序的自定義組件中,需要使用多 插槽時,可以在組件的 .js
文件中
7.4 定義多個插槽
可以在組件的 .wxml
中使用多個 標籤,以不同的 name
來區分不同的插槽
8. 父子組件通訊
8.1 瞭解父子組件之間通信的 3 個方式
-
屬性綁定
- 用於父組件向子組件的指定屬性設置數據,僅能設置
JSON
兼容的數據(只能傳遞數據,不能傳遞方法)
- 用於父組件向子組件的指定屬性設置數據,僅能設置
-
事件綁定
- 用於子組件向父組件傳遞數據,可以傳遞任意數據(包括數組和方法)
-
獲取組件實例
- 父組件還可以通過
this.selectComponent()
獲取子組件實例對象這樣就可以直接訪問子組件的任意數據和方法
- 父組件還可以通過
8.2 屬性綁定
-
傳遞數據
- 屬性綁定用於實現父向子傳值,而且只能傳遞普通類型的數據,無法將方法傳遞給子組件
-
接收數據
- 子組件在 properties 節點中聲明對應的屬性並使用
8.3 實現子組件的 count 屬性自增 + 1
js
data: {
count: 0
}
js
addCount() {
this.setData({
count: this.data.count + 1
})
}
8.4 瞭解事件綁定的 4 個核心實現步驟
-
事件綁定用於實現子向父傳值,可以傳遞任何類型的數據。使用步驟如下:
- 在
父組件
的js
中,定義一個函數,這個函數即將通過自定義事件的形式,傳遞給子組件 - 在
父組件
的wxml
中,通過自定義事件的形式,將步驟 1 中定義的函數引用,傳遞給子組件 - 在
子組件
的js
中,通過調用this.triggerEvent('自定義事件名稱', {/* 參數對象 */})
,將數據發送到父組件 - 在父組件的
js
中,通過e.detail
獲取到子組件傳遞過來的數據
- 在
8.5 瞭解事件綁定的核心實現代碼
-
步驟 1: 在父組件的
js
中,定義一個函數,這個函數即將通過自定義事件的形式,傳遞給子組件 -
步驟 2:在父組件的
wxml
中,通過自定義事件的形式,將 步驟 1 中定義的函數引用,傳遞給子組件 -
步驟 3:在
子組件
的js
中,通過調用this.triggerEvent('自定義事件名稱', {/* 參數對象 */})
,將數據發送到父組件 -
步驟 4:在父組件的
js
中,通過e.detail
獲取到子組件傳遞過來的數據
8.6 使用 selectComponent 獲取組件實例
可在父組件裏調用 this.selectComponent("id或class選擇器")
,獲取子組件的實例對象,從而直接訪問子組件的任意數據和方法。調用時需要傳入一個選擇器
,例如 this.selectComponent(".my-component")
9. 使用 npm
9.1 小程序對 npm 的支持和限制
目前,小程序中已經支持使用 npm 安裝第三方包,從而來提高小程序的開發效率。但是,在小程序中使用 npm 包有如下 3 個限制:
-
不支持依賴於 Node.js 內置庫的包
- 不支持依賴於 Node 核心模塊的包
- fs Node 文件系統模塊 -- 不支持
- path Node 路徑模塊 -- 不支持
-
不支持依賴於瀏覽器內置對象的包
- 小程序的宿主環境是微信,不存在 DOM 和 DOM
- 所以依賴於內置對象的包,也不能夠使用
-
不支持依賴於 C++ 插件的包
總結:雖然 npm 上的包有千千萬,但是能供小程序使用的包卻“為數不多”
9.2 瞭解什麼是 vant Weapp
Vant
是有贊前端團隊開源的移動端組件庫,於 2016 年開源,已持續維護 4 年時間。Vant
對內承載了有贊所有核心業務,對外服務十多萬開發者,是業界主流的移動端組件庫之一- 採用
MIT
開源許可協議,對商業使用比較友好 - 掃描下方小程序二維碼,體驗組件庫示例
9.3 安裝 Vant 組件庫
在小程序項目中,安裝 Vant 組件庫主要分為如下幾步
-
通過
npm
安裝- 注意:項目目錄不能存在中文!不能存在中文!不能存在中文!否則會報錯 !
shell
npm init -y
shell
npm i @vant/[email protected] -S --production
-
構建
npm
包功能如果提示構建失敗,可以將微信開發者工具重啟,重啟以後,運行小程序項目,查看是否還報錯
-
建議先點擊
微信開發者工具
-->詳情
-->本地設置
-->使用 npm 模塊
-
然後點擊
微信開發者工具
-->菜單欄
-->工具
-->構建npm
-
提示
構建成功,耗時 xxx 秒
且控制枱沒有任何的錯誤,説明包構建成功,可以進行使用- 否則就需要把
node_modules
、miniprogram_npm
刪除 - 刪除以後,重新安裝包,並點擊
工具
-->構建npm
,進行重新構建
- 否則就需要把
-
-
修改
app.json
- 將
styles: v2
進行移除,防止小程序本身的 UI 樣式和 Vant 的組件樣式庫 衝突
- 將
詳細的操作地址:安裝 vant Weapp
9.4 使用 Vant 組件
安裝完 Vant
組件庫之後,可以在 app.json
的 usingComponents
節點中引入需要的組件,即可在 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
-
自定義屬性
(有時候也被稱作CSS變量
或者級聯變量
)是由CSS
作者定義的,它包含的值可以在整個文檔中重複使用 -
由自定義屬性標記設定值
- 聲明一個自定義屬性,屬性名需要以兩個減號(
--
)開始,屬性值則可以是任何有效的CSS
值 - 比如:
--main-color: black;
- 聲明一個自定義屬性,屬性名需要以兩個減號(
-
由var() 函數來獲取值
color: var(--main-color);
```html
```
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 化
-
基於回調函數的異步
API
的缺點-
默認情況下,小程序官方提供的異步 API 都是基於回調函數實現的,例如,網絡請求的 API 需要按照如下的方式調用
-
這種代碼的缺點是顯而易見的, 容易造成回調地獄的問題,代碼的可讀性、維護性差!而我們就想將這種類型的代碼使用
API Promise
化進行改造
-
-
什麼是
API Promise
化API Promise
化,指的是通過額外的配置,將官方提供的、基於回調函數的異步API
,升級改造為基於Promise
的異步API
,從而提高代碼的可讀性、維護性,避免回調地獄的問題
9.8 安裝並構建 miniprogram-api-promise
-
在小程序中,實現
API Promise
化主要依賴於miniprogram-api-promise
這個第三方的npm
包js npm i --save [email protected]
-
下載完成,我們不能直接使用這個包,而是需要再次重新構建npm包
- 建議在構建前先刪除原有的
miniprogram_npm
- 然後再點擊工具,構建
npm
- 建議在構建前先刪除原有的
-
如果刪除了
miniprogram_npm
目錄,構建還是失敗- 需要把
node_modules
、miniprogram_npm
刪除 - 刪除以後,重新安裝包,重新安裝以後,再次進行構建
- 需要把
9.9 三個步驟實現 API 的 Promise 化
-
在小程序入口文件中調用一次
promisifyAll()
方法js import { promisifyAll } from 'miniprogram-api-promise'
-
聲明一個常量,為一個空對象
js const wxp = wx.p = {}
-
調用
promisifyAll()
方法js promisifyAll(wx, wxp)
-
上述代碼是什麼含義呢 ?
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)
}