自定義組件
1. 創建-注冊-使用組件
組件介紹
小程序目前已經支持組件化開發,可以將頁面中的功能模塊抽取成自定義組件,以便在不同的頁面中重復使用;
也可以將復雜的頁面拆分成多個低耦合的模塊,有助于代碼維護。
開發中常見的組件有兩種:
- 公共組件:將頁面內的功能模塊抽象成自定義組件,以便在不同的頁面中重復使用
- 頁面組件:將復雜的頁面拆分成多個低耦合的模塊,有助于代碼維護
如果是公共組件,建議將其放在小程序的目錄下的 components
文件夾中
如果是頁面組件,建議將其放在小程序對應頁面目錄下,當然你也可以放到頁面的 components
文件夾中
同時建議:一個組件一個文件夾,文件夾名稱和組件名稱保持一致
📌 注意事項:
- 自定義組件的需要在
json
文件中需要配置component
字段設為true
- 自定義組件通過
Component
構造器進行構建,在構造器中可以指定組件的屬性、數據、方法等
創建自定義組件:
創建組件的步驟很簡單,以公共組件為例,創建的步驟如下:
-
在小程序的目錄下新建
components
文件夾 -
在
components
文件夾上,點擊右鍵,選擇新建文件夾
,然后輸入文件夾名稱,我們建議文件夾的名稱和組件的名稱保持一致,這樣方便后期對組件進行維護。我們這里新的的組件名稱叫做:custom-checkbox
-
在新建的組件文件夾上,點擊右鍵,選擇
新建 Component
,然后輸入組件的名稱,組件的名稱建議和文件夾保持一致 -
此時就已經創建了一個功能組件
使用自定義組件
開發中常見的組件主要分為 公共組件 和 頁面組件 兩種,因此注冊組件的方式也分為兩種:
- 全局注冊:在
app.json
文件中配置usingComponents
節點進行引用聲明,注冊后可在任意組件使用 - 局部注冊:在頁面的
json
文件中配置usingComponents
節點進行引用聲明,只可在當前頁面使用
在配置 usingComponents
節點進行引用聲明時,需要提供自定義組件的標簽名和對應的自定義組件文件路徑,語法如下:
{"usingComponents": {"自定義組件的標簽名": "自定義組件文件路徑"}
}
這樣,在頁面的 wxml
中就可以像使用基礎組件一樣使用自定義組件。節點名即自定義組件的標簽名,節點屬性即傳遞給組件的屬性值。
{"usingComponents": {"custom-checkbox": "/components/custom-checkbox/custom-checkbox"}
}
<!--pages/index/index.wxml--><view><!-- 將導入的自定義組件當成標簽使用 --><custom-checkbox/>
</view>
2. 自定義組件-數據和方法
在組件的 .js 中,需要調用 Component
方法創建自定義組件,Component
中有以下兩個屬性:
data
數據:組件的內部數據
methods
方法:在組件中事件處理程序需要寫到 methods
中才可以
落地代碼:
?? components/custom-checkbox/custom-checkbox.wxml
<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定義組件</text> --><view class="custom-checkbox-container"><view class="custom-checkbox-box"><checkbox checked="{{ isChecked }}" bindtap="updateChecked" /></view>
</view>
?? components/custom-checkbox/custom-checkbox.wxss
/* components/custom-checkbox/custom-checkbox.wxss */.custom-checkbox-container {display: inline-block;
}
?? components/custom-checkbox/custom-checkbox.js
Component({/*** 組件的初始數據:用來定義當前組件內部所需要使用的數據*/data: {isChecked: false},/*** 組件的方法列表:在組件中,所有的事件處理程序都需要寫到 methods 方法中*/methods: {// 更新復選框的狀態updateChecked () {this.setData({isChecked: !this.data.isChecked})console.log(this.data.isChecked)}}})
?? app.json
{"usingComponents": {"custom-checkbox": "./components/custom-checkbox/custom-checkbox"}
}
?? index.wxml
<custom-checkbox /><view class="line"></view><custom-checkbox />
3. 自定義組件-屬性
屬性 Properties 是指組件的對外屬性,主要用來接收組件使用者傳遞給組件內部的數據,和 data 一同用于組件的模板渲染
📌 注意事項:
- 設置屬性類型需要使用 type 屬性,屬性類型是必填項,value 屬性為默認值
- 屬性類型可以為 String、Number、Boolean、Object、Array ,也可以為 null 表示不限制類型
落地代碼:
?? index.wxml
<!-- label 文本顯示的內容 -->
<!-- position 控制文本顯示的位置 --><custom-checkbox label="我已閱讀并同意 用戶協議 和 隱私協議" position="right" /><view class="line"></view><custom-checkbox label="匿名提交" position="left" />
?? components/custom-checkbox/custom-checkbox.wxml
<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定義組件</text> --><view class="custom-checkbox-container">
+ <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+ <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />
+
+ <view>
+ <text>{{ label }}</text>
+ </view></view>
</view>
?? components/custom-checkbox/custom-checkbox.wxss
/* components/custom-checkbox/custom-checkbox.wxss */.custom-checkbox-container {display: inline-block;
}.custom-checkbox-box {display: flex;align-items: center;
}.custom-checkbox-box.left {flex-direction: row-reverse;
}.custom-checkbox-box.right {flex-direction: row;
}.custom-checkbox {margin-left: 10rpx;
}
?? components/custom-checkbox/custom-checkbox.js
Component({+ /**
+ * 組件的屬性列表:組件的對外屬性,主要用來接收組件使用者傳遞給組件內部的屬性以及數據
+ */
+ properties: {
+ // 如果需要接收傳遞的屬性,有兩種方式:全寫、簡寫
+ // label: String
+
+ label: {
+ // type 組件使用者傳遞的數據類型
+ // 數據類型:String、Number、Boolean、Object、Array
+ // 也可以設置為 null,表示不限制類型
+ type: String,
+ value: ''
+ },
+
+ // 文字顯示位置
+ position: {
+ type: String,
+ value: 'right'
+ }
+ },/*** 組件的初始數據:用來定義當前組件內部所需要使用的數據*/data: {isChecked: false},/*** 組件的方法列表:在組件中,所有的事件處理程序都需要寫到 methods 方法中*/methods: {// 更新復選框的狀態updateChecked () {this.setData({isChecked: !this.data.isChecked,
+ // label: '在組件內部也可以修改 properties 中的數據'})+ // 在 JS 中可以訪問和獲取 properties 中的數據
+ // 但是一般情況下,不建議修改,因為會造成數據流的混亂
+ // console.log(this.properties.label)// console.log(this.data.isChecked)}}})
4. 組件 wxml 的 slot
在使用基礎組件時,可以給組件傳遞子節點傳遞內容,從而將內容展示到頁面中,自定義組件也可以接收子節點內容
只不過在組件模板中需要定義 <slot />
節點,用于承載組件引用時提供的子節點
默認情況下,一個組件的 wxml 中只能有一個 slot 。需要使用多 slot 時,可以在組件 js 中聲明啟用。
同時需要給 slot 添加 name 來區分不同的 slot,給子節點內容添加 slot 屬性來將節點插入到 對應的 slot 中
知識點講解:
?? custom01.html
<view><slot name="slot-top" /><!-- slot 就是用來接收、承載子節點內容 --><!-- slot 只是一個占位符,子節點內容會將 slot 進行替換 --><!-- 默認插槽 --><view><slot /></view><slot name="slot-bottom" />
</view>
?? custom01.js
// components/custom01/custom01.jsComponent({options: {// 啟用多 slot 支持multipleSlots: true}})
?? cart.wxml
<custom01><text slot="slot-top">我需要顯示到頂部</text><!-- 默認情況下,自定義組件的子節點內容不會進行展示 --><!-- 如果想內容進行展示,需要再組件模板中定義 slot 節點 -->我是子節點內容<text slot="slot-bottom">我需要顯示到低部</text>
</custom01>
完善復選框案例
?? custom-checkbox.html
<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定義組件</text> --><view class="custom-checkbox-container"><view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}"><checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" />+ <view>
+ <!-- lable 和 子節點內容都進行了展示 -->
+ <!-- 要么展示 lable 要么展示 子節點內容 -->
+ <!-- 如果用戶傳遞了 lable 屬性,就展示 lable -->
+ <!-- 如果用戶沒有傳遞 lable 屬性,就展示 子節點內容 -->
+ <text wx:if="{{ label !== '' }}">{{ label }}</text>
+
+ <slot wx:else />
+ </view></view>
</view>
?? index.html
<!-- label 文本顯示的內容 -->
<!-- position 控制文本顯示的位置 -->
<custom-checkbox label="我已閱讀并同意 用戶協議 和 隱私協議" position="right">我已閱讀并同意 用戶協議 和 隱私協議 - 111
</custom-checkbox><view class="line"></view><custom-checkbox label="匿名提交" position="left">匿名提交 - 222
</custom-checkbox>
5. 組件樣式以及注意事項
選擇器使用注意事項:
類似于頁面,自定義組件擁有自己的 wxss
樣式,組件對應 wxss
文件的樣式,只對組件wxml內的節點生效。
編寫組件樣式時,需要注意以下幾點:
-
app.wxss 或頁面的 wxss 中使用了標簽名(view)選擇器(或一些其他特殊選擇器)來直接指定樣式
這些選擇器會影響到頁面和全部組件,通常情況下這是不推薦的做法 -
組件和引用組件的頁面不能使用 id 選擇器(#a)、屬性選擇器([a]) 和 標簽名選擇器,請改用 class 選擇器
-
組件和引用組件的頁面中使用后代選擇器(.a .b)在一些極端情況下會有非預期的表現,如遇,請避免使用
-
子元素選擇器(.a>.b)只能用于 view 組件與其子節點之間,用于其他組件可能導致非預期的情況。
-
繼承樣式,如 font 、 color ,會從組件外繼承到組件內。
-
除繼承樣式外, 全局中的樣式、組件所在頁面的的樣式對自定義組件無效 (除非更改組件樣式隔離選項)
#a { } /* 在組件中不能使用 */
[a] { } /* 在組件中不能使用 */
button { } /* 在組件中不能使用 */
.a > .b { } /* 除非 .a 是 view 組件節點,否則不一定會生效 */
落地代碼:
?? custom02.wxml
<text id="content" class="content son"><text class="label">給自定義組件設置樣式</text>
</text>
?? custom02.wxss
/* components/custom02/custom02.wxss *//* 第一個注意事項:在自定義的 wxss 文件中,不允許使用標簽選擇器,ID 選擇器,屬性選擇器 */
/* 請改為 class 選擇器 */
/* text {color: lightseagreen;
} *//* #content {color: lightseagreen;
} *//* [id=content] {color: lightseagreen;
} *//* .content {color: lightseagreen;
} *//* 第二個注意事項:子選擇器,只能用于 view 和 子組件,用于其他組件可能會出現樣式失效的問題 */
/* .content > .label {color: lightseagreen;
} *//* 第三個注意事項:繼承樣式,例如:color\font 都會從組件外繼承 *//* 第四個注意事項:全局樣式、組件所在頁面的樣式文件中的樣式都對自定義組件無效 *//* 第五個注意事項:官方不推薦做法 */
/* 不建議在 全局樣式文件 以及 父級頁面之間使用標簽選擇器設置樣式 */
/* 如果是在全局樣式文件中設置樣式,會影響項目中全部的相同組件 */
/* 如果是再頁面樣式文件中設置樣式,會影響當前頁面所有的相同組件 *//* 第六個注意事項: */
/* 組件和組件使用者,如果使用了后代選擇器,可能會出現一些非預期情況 */
/* 如果出現,請避免 */
?? cate.wxml
<view class="custom parent"><view><custom02 /><view class="son test">我是父級頁面中的結構</view></view>
</view>
?? cate.wxss
/* pages/cate/cate.wxss *//* .custom {color: lightseagreen;font-size: 50rpx;
} *//* .label {color: lightseagreen;
} *//* text {color: lightseagreen;
} */.parent .son.test {color: lightsalmon;
}
?? app.wxss
/* .label {color: lightseagreen;
} *//* text {color: lightseagreen;
} */
6. 組件樣式隔離
默認情況下,自定義組件的樣式只受到自定義組件 wxss 的影響。除非以下兩種情況:
-
app.wxss
或頁面的wxss
中使用了標簽名(view)選擇器(或一些其他特殊選擇器)來直接指定樣式,這些選擇器會影響到頁面和全部組件。通常情況下這是不推薦的做法。 -
指定特殊的樣式隔離選項
styleIsolation
Component({options: {styleIsolation: 'isolated'} })
styleIsolation
選項它支持以下取值:
isolated
表示啟用樣式隔離,在自定義組件內外,使用 class 指定的樣式將不會相互影響(一般情況下的默認值);apply-shared
表示頁面 wxss 樣式將影響到自定義組件,但自定義組件 wxss 中指定的樣式不會影響頁面;shared
表示頁面 wxss 樣式將影響到自定義組件,自定義組件 wxss 中指定的樣式也會影響頁面和其他設置了apply-shared
或shared
的自定義組件。
落地代碼:
?? custom03.wxml
<!--components/custom03/custom03.wxml--><text class="label">演示組件樣式隔離</text>
?? custom03.wxss
/* components/custom03/custom03.wxss */.test {color: lightseagreen;font-size: 50rpx;
}
?? custom03.js
// components/custom03/custom03.js
Component({options: {// styleIsolation:配置組件樣式隔離// isolated:開啟樣式隔離,默認值// 在默認情況下,自定義組件和組件使用者如果存在相同的類名,類名不會相互影響// apply-shared:表示組件使用者、頁面的 wxss 樣式能夠影響到自定義組件// 但是自定義組件的樣式不會影響組件使用者、頁面的 wxss 樣式// styleIsolation: "apply-shared"// shared:表示組件使用者、頁面的 wxss 樣式能夠影響到自定義組件// 自定義組件的樣式會影響組件使用者、頁面的 wxss 樣式// 和其他使用了 apply-share 以及 share 屬性的自定義組件styleIsolation: 'shared'}})
?? cate.wxml
<custom03 />
?? cate.wxss
.label {color: lightsalmon;
}
7. 拓展-小程序修改checkbox樣式
知識點:
技巧:在官方文檔,找到官方提供的案例,審查元素,就能看到對應的類名
📌 注意事項
- .custom-checkbox .wx-checkbox-input {}:復選框沒有選中時默認的樣式
- .custom-checkbox .wx-checkbox-input-checked {}: 復選框選中時默認的樣式
- .custom-checkbox .wx-checkbox-input.wx-checkbox-input-checked:before {}:復選框選中時 √ 樣式
這幾個類名,在全局樣式文件、頁面樣式文件都可以對修改復選框樣式,
但是在自定義組件內部使用的時候,需要添加 styleIsolation: 'shared' 屬性
落地代碼:
?? components/custom-checkbox/custom-checkbox.wxss
/* 復選框組件是公共組件 */
/* 以后需要再多個頁面或者需要再多個項目中進行使用 */
/* 所以呢,需要先給復選框組件準備、設置一些默認樣式 */
/* 如果在其他頁面或者其他項目中使用的時候,發現樣式不符合產品需求 */
/* 可以進行修改、對默認的樣式進行修改 *//* 1. 需要給復選框設置默認樣式 */
/* 需要先找到小程序給復選框提供的類名,通過小程序給提供的類名修改才可以 */
/* 需要先打開小程序開發文檔,找到復選框文檔,審查元素,進行查找 *//* 在自定義組件中,不能直接修改復選框樣式 */
/* 如果需要進行修改,需要設置 styleIsolation 才可以 */
/* shared:修改其他頁面的樣式、組件使用者的樣式、以及其他使用了 share 以及 apply-share 的組件 */
/* 這時候,不是想要的結果 */
/* 需求是:只想影響當前組件,可以添加命名空間 *//* 復選框沒有選中時默認的樣式 */
.custom-checkbox .wx-checkbox-input {width: 24rpx !important;height: 24rpx !important;border-radius: 50% !important;border: 1px solid #fda007 !important;margin-top: -6rpx;
}/* 復選框選中時默認的樣式 */
.custom-checkbox .wx-checkbox-input-checked {background-color: #fda007 !important;
}/* 復選框選中時 √ 樣式 */
.custom-checkbox .wx-checkbox-input.wx-checkbox-input-checked:before {font-size: 22rpx;color: #fff;
}/* 2. 組件使用者也能夠修改默認的樣式 */
?? components/custom-checkbox/custom-checkbox.js
Component({options: {styleIsolation: 'shared'}})
?? index.wxss
/* 組件使用者修改復選框的樣式 */
.custom .custom-checkbox .wx-checkbox-input {border: 1px solid lightseagreen !important;
}.custom .custom-checkbox .wx-checkbox-input-checked {background-color: lightseagreen !important;
}
8. 數據監聽器
知識點:
數據監聽器可以用于監聽和響應任何屬性和數據字段的變化,有時,需要在一些數據字段被 setData 設置時,需要執行一些操作。那么就可以使用 observers
數據監聽器來實現。語法如下:
Component({data: {num: 10,count: 1,obj: { name: 'Tom', age: 10 },arr: [1, 2, 3]},observers: {// key 是需要檢測數據// value 是一個函數,函數接收一個形參作為參數,是最新的值num: function(newNum) {console.log(newNum)},// 數據監聽器支持監聽屬性或內部數據的變化,可以同時監聽多個'num, count': function (newNum, newCount) {console.log(newNum, newCount)}// 監聽器可以監聽子數據字段'obj.age': function(newAge) {console.log(newAge)},// 如果需要監聽所有子數據字段的變化,可以使用通配符 ** 'obj.**': function(newAge) {console.log(newAge)},'arr[0]': function (val) {}}
})
9. 組件間通信與事件
9.1 父往子傳值
知識點:
父組件如果需要向子組件傳遞指定屬性的數據,在 WXML 中需要使用數據綁定的方式
與普通的 WXML 模板類似,使用數據綁定,這樣就可以向子組件的屬性傳遞動態數據。
父組件如果需要向子組件傳遞數據,只需要兩個步驟:
1.在父組件 WXML 中使用 數據綁定 的方式向子組件傳遞動態數據
2.子組件內部使用 properties 接收父組件傳遞的數據即可
知識點代碼:
<!-- 引用組件的頁面模板 -->
<view><costom prop-a="{{ name }}" prop-b="{{ age }}" />
</view>
在組件內部,需要在 Component
構造器中通過 properties
接收傳遞的數據,接收方式有兩種:
Component({/*** 組件的屬性列表 props*/properties: {propA: {type: String, // 傳遞的數據類型value: '' // 默認值},propB: Number // 簡化的定義方式},// coding...
})
在子組件中也可以通過 this.setData()
對 properties
中的數據進行修改,但是一般不建議修改
// components/custom01/custom01.js
Component({/*** 組件的方法列表*/methods: {// 修改列表中的數據updateProp () {this.setData({propB: this.properties.propB + 1})}}
})
復選框組件案例:
?? index.js
Page({data: {isChecked: true},// coding...})
?? index.wxml
<custom-checkboxlabel="我已閱讀并同意 用戶協議 和 隱私協議"position="right"
+ checked="{{ isChecked }}">我已閱讀并同意 用戶協議 和 隱私協議 - 111
</custom-checkbox>
?? components/custom-checkbox/custom-checkbox.js
Component({options: {styleIsolation: 'shared'},properties: {// coding...// 復選框組件公共組件// 需要再多個頁面、在多個項目中進行使用// 在使用的時候,有的地方希望默認是選中的效果,有的地方希望默認是沒有被選中的效果// 怎么處理 ?// 首先讓復選框默認還是沒有被選中的效果// 如果希望復選框默認被選中,這時候傳遞屬性(checked=true)到復選框組件
+ checked: {
+ type: Boolean,
+ value: false
+ }},/*** 組件的初始數據:用來定義當前組件內部所需要使用的數據*/data: {isChecked: false},+ observers: {
+ // 如果需要將 properties 中的數據賦值給 data
+ // 可以使用 observers 進行處理
+ checked: function (newChecked) {
+ // console.log(newChecked)
+ this.setData({
+ isChecked: newChecked
+ })
+ }
+ },/*** 組件的方法列表:在組件中,所有的事件處理程序都需要寫到 methods 方法中*/methods: {// 更新復選框的狀態updateChecked () {this.setData({
+ isChecked: !this.data.isChecked,
+ // checked: !this.properties.checked// label: '在組件內部也可以修改 properties 中的數據'})// 在 JS 中可以訪問和獲取 properties 中的數據// 但是一般情況下,不建議修改,因為會造成數據流的混亂// console.log(this.properties.label)// console.log(this.data.isChecked)}}})
?? components/custom-checkbox/custom-checkbox.wxml
<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定義組件</text> --><view class="custom-checkbox-container"><view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+ <checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" /><view class="content"><!-- lable 和 子節點內容都進行了展示 --><!-- 要么展示 lable 要么展示 子節點內容 --><!-- 如果用戶傳遞了 lable 屬性,就展示 lable --><!-- 如果用戶沒有傳遞 lable 屬性,就展示 子節點內容 --><text wx:if="{{ label !== '' }}">{{ label }}</text><slot wx:else /></view></view>
</view>
9.2 子往父傳值
子組件如果需要向父組件傳遞數據,可以通過小程序提供的事件系統實現傳遞傳遞,可以傳遞任意數據。
事件系統是組件間通信的主要方式之一,自定義組件可以觸發任意的事件,引用組件的頁面可以監聽這些事件,流程如下:
- 自定義組件觸發事件時,需要使用
triggerEvent
方法發射一個自定義的事件 - 自定義組件標簽上通過 bind 方法監聽發射的事件
觸發事件:
<!-- 在自定義組件中 -->
<button type="primary" plain bindtap="sendData">傳遞數據</button>
// components/custom05/custom05.js
Component({// 組件的初始數據data: {num: 666},// 組件的方法列表methods: {// 將數據傳遞給父組件sendData () {// 如果需要將數據傳遞給父組件// 需要使用 triggerEvent 發射自定義事件// 第二個參數,是攜帶的參數this.triggerEvent('myevent', this.data.num)}}
})
監聽事件:
<view>{{ num }}</view>
<!-- 需要在自定義組件標簽上通過 bind 方法綁定自定義事件,同時綁定事件處理函數 -->
<custom05 bind:myevent="getData" />
Page({data: {num: ''},getData (event) {// 可以通過事件對象.detail 獲取子組件傳遞給父組件的數據// console.log(event)this.setData({num: event.detail})}})
復選框組件案例:
?? components/custom-checkbox/custom-checkbox.js
Component({/*** 組件的方法列表:在組件中,所有的事件處理程序都需要寫到 methods 方法中*/methods: {// 更新復選框的狀態updateChecked () {this.setData({isChecked: !this.data.isChecked,// label: '在組件內部也可以修改 properties 中的數據'})// 在 JS 中可以訪問和獲取 properties 中的數據// 但是一般情況下,不建議修改,因為會造成數據流的混亂// console.log(this.properties.label)// console.log(this.data.isChecked)+ // 目前復選框組件的狀態是存儲在復選框組件內部的、存儲在自定義組件內部的
+ // 但是,在以后實際開發中,組件使用者、父組件有時候也需要獲取到復選框內部的狀態
+ // 怎么辦 ?
+ // 這時候,自定義組件內部就需要發射一個自定義事件,
+ // 如果組件使用者、父組件需要使用數據,綁定自定義事件進行獲取即可
+ this.triggerEvent('changechecked', this.data.isChecked)}}})
?? index.html
<custom-checkboxlabel="我已閱讀并同意 用戶協議 和 隱私協議"position="right"checked="{{ isChecked }}"class="getchild"
+ bind:changechecked="getData"
>我已閱讀并同意 用戶協議 和 隱私協議 - 111
</custom-checkbox>
?? index.js
Page({data: {isChecked: true},getData (event) {console.log(event.detail)if (event.detail) {console.log('提交')} else {console.log('請同意協議!')}}})
9.3 獲取組件實例
如果前面兩種方式不足以滿足需要。
可在父組件里調用 this.selectComponent()
,獲取子組件的實例對象,就可以直接拿到子組件的任意數據和方法。調用時需要傳入一個匹配選擇器 selector
,如:this.selectComponent(".my-component")
。
<!-- 父組件 -->
<costom bind:myevent="getData" class="custom" />
<button bindtap="getChildComponent"></button>
// 父組件
Page({data: {},getChildComponent: function () {const child = this.selectComponent('.custom')console.log(child)}
})
復選框組件案例:
?? index.html
<custom-checkboxlabel="我已閱讀并同意 用戶協議 和 隱私協議"position="right"checked="{{ isChecked }}"
+ class="child"
+ id="child"bind:changechecked="getData"
>我已閱讀并同意 用戶協議 和 隱私協議 - 111
</custom-checkbox><button type="primary" plain bindtap="getChild">獲取子組件實例對象</button>
?? index.js
Page({// coding...// 獲取子組件的實例對象getChild () {// this.selectComponent 方法獲取子組件實例對象// 獲取到實例對象以后,就能獲取子組件所有的數據、也能調用子組件的方法const res = this.selectComponent('#child')console.log(res.data.isChecked)}})
10. 組件生命周期
組件的生命周期:指的是組件自身的一些鉤子函數,這些函數在特定的時間節點時被自動觸發
組件的生命周期函數需要在 lifetimes
字段內進行聲明
最重要的生命周期是 created
attached
detached
包含一個組件生命周期流程的最主要時間點
定義段 | 描述 |
---|---|
created | 在組件實例剛剛被創建時執行,注意此時不能調用 setData (還沒有對模板解析) |
attached | 在組件實例進入頁面節點樹時執行 (模板已經解析完畢,并且掛載到頁面上) |
ready | 在組件布局完成后執行 |
moved | 在組件實例被移動到節點樹另一個位置時執行 |
detached | 在組件實例被從頁面節點樹移除時執行 (組件被銷毀了) |
![]() |
-
【組件實例剛剛被創建好時】,
created
生命周期被觸發。此時,組件數據this.data
就是在Component
構造器中定義的數據data
。 此時還不能調用setData
。 通常情況下,這個生命周期只應該用于給組件this
添加一些自定義屬性字段。 -
【在組件完全初始化完畢】、進入頁面節點樹后,
attached
生命周期被觸發。此時,this.data
已被初始化為組件的當前值。這個生命周期很有用,絕大多數初始化工作可以在這個時機進行。 -
【在組件離開頁面節點樹后】,
detached
生命周期被觸發。退出一個頁面時,如果組件還在頁面節點樹中,則detached
會被觸發。
Component({lifetimes: {created: function () {// 在組件實例剛剛被創建時執行,注意此時不能調用 setData // 一般用來為組件添加一些自定義屬性字段。},attached: function() {// attached 在組件完全初始化完畢、進入頁面節點樹后執行// 模板已經解析完畢,并且掛載到頁面上// 一般都是在這里寫對應的交互},detached: function() {// 在組件實例被從頁面節點樹移除時執行},// coding...}// coding...
})
11. 組件所在頁面的生命周期
組件還有一些特殊的生命周期,這類生命周期和組件沒有很強的關聯
主要用于組件內部監聽父組件的展示、隱藏狀態,從而方便組件內部執行一些業務邏輯的處理
組件所在頁面的生命周期有 4 個: show、 hide、 resize、 routeDone,需要在 pageLifetimes
字段內進行聲明
// components/custom06/custom06.js
Component({// coding...// 組件所在頁面的生命周期pageLifetimes: {// 監聽組件所在的頁面展示(后臺切前臺)狀態show () {console.log('組件所在的頁面被展示')},// 監聽組件所在的頁面隱藏(前臺切后臺、點擊 tabBar)狀態hide () {console.log('組件所在的頁面被隱藏')}}})
12. 小程序生命周期總結
小程序冷啟動,鉤子函數執行的順序
保留當前頁面(navigate) 以及 關閉當前頁面(redirect)
切后臺 以及 切前臺(熱啟動)
13. 拓展:使用 Component 構造頁面
Component 方法用于創建自定義組件
小程序的頁面也可以視為自定義組件,因此頁面也可以使用 Component 方法進行創建,從而實現復雜的頁面邏輯開發
📌 注意事項:
要求對應 json 文件中包含 usingComponents 定義段
頁面使用 Component 構造器創建,需要定義與普通組件一樣的字段與實例方法
頁面 Page 中的一些生命周期方法(如 onLoad() 等以“on”開頭的方法),在 Component 中要寫在 methods 屬性中才能生效
組件的屬性 Properties 可以用于接收頁面的參數,在 onLoad() 中可以通過 this.data 拿到對應的頁面參數
落地代碼:
Component({// 為什么需要使用 Component 方法進行構造頁面// Component 方法功能比 Page 方法強大很多// 如果使用 Component 方法構造頁面,可以實現更加復雜的頁面邏輯開發// 小程序頁面也可以使用 Component 方法進行構造// 注意事項:// 1. 要求 .json 文件中必須包含 usingComponents 字段// 2. 里面的配置項需要和 Component 中的配置項保持一致// 3. 頁面中 Page 方法有一些鉤子函數、事件監聽方法,這些鉤子函數、事件監聽方法必須方法 methods 對象中// 4. 組件的屬性 properties 也可以接受頁面的參數,在 onLoad 鉤子函數中可以通過 this.data 進行獲取properties: {id: String,title: String},data: {name: 'tom'},// onLoad () {// console.log('頁面加載 - 1')// },methods: {// 更新 nameupdateName() {this.setData({name: 'jerry'})},onLoad (options) {// console.log('頁面加載 - 2')// console.log(options)console.log(this.data.id)console.log(this.data.title)console.log(this.properties.id)},}})
14. 拓展:behaviors
小程序的 behaviors 方法是一種代碼復用的方式,可以將一些通用的邏輯和方法提取出來,然后在多個組件中復用,從而減少代碼冗余,提高代碼的可維護性。
如果需要 behavior 復用代碼,需要使用 Behavior() 方法,每個 behavior 可以包含一組屬性、數據、生命周期函數和方法
組件引用它時,它的屬性、數據和方法會被合并到組件中,生命周期函數也會在對應時機被調用。
注冊 behavior:
如果需要注冊一個 behavior
,需要借助 Behavior()
方法,接受一個 Object
類型的參數
// my-behavior.jsmodule.exports = Behavior({behaviors: [],properties: {myBehaviorProperty: {type: String}},data: {myBehaviorData: 'my-behavior-data'},created: function () {console.log('[my-behavior] created')},attached: function () {console.log('[my-behavior] attached')},ready: function () {console.log('[my-behavior] ready')},methods: {myBehaviorMethod: function () {console.log('[my-behavior] log by myBehaviorMehtod')},}
})
使用 behavior:
// my-component.js
const myBehavior = require('my-behavior')Component({behaviors: [myBehavior]// coding...
})
組件和它引用的 behavior 中可以包含同名的字段,對這些字段的處理方法如下:
-
如果有同名的屬性或方法,采用 “就近原則”,組件會覆蓋 behavior 中的同名屬性或方法
-
如果有同名的數據字段且都是對象類型,會進行對象合并,其余情況會 采用 “就近原則” 進行數據覆蓋
-
生命周期函數和 observers 不會相互覆蓋,會是在對應觸發時機被逐個調用,也就是都會被執行
詳細的規則:同名字段的覆蓋和組合規則
15. 拓展:外部樣式類
默認情況下,組件和組件使用者之間如果存在相同的類名不會相互影響,組件使用者如果想修改組件的樣式,需要就解除樣式隔離,但是解除樣式隔離以后,在極端情況下,會產生樣式沖突、CSS 嵌套太深等問題,從而給我們的開發帶來一定的麻煩。
外部樣式類:在使用組件時,組件使用者可以給組件傳入 CSS 類名,通過傳入的類名修改組件的樣式。
如果需要使用外部樣式類修改組件的樣式,在 Component 中需要用 externalClasses 定義若干個外部樣式類。
外部樣式類的使用步驟:
1.在 Component 中用 externalClasses 定義段定義若干個外部樣式類
2.自定義組件標簽通過 屬性綁定 的方式提供一個樣式類,屬性是 externalClasses 定義的元素,屬性值是傳遞的類名
3.將接受到的樣式類用于自定義組件內部
📌注意事項:
? 在同一個節點上使用普通樣式類和外部樣式類時,兩個類的優先級是未定義的
? 因此需要添加 !important 以保證外部樣式類的優先級
落地代碼:
?? custom09.js
// components/custom09/custom09.js
Component({// 組件接受的外部樣式類externalClasses: ['extend-class']
})
?? custom09.wxml
<!-- 在同一個節點上,如果存在外部樣式類 和 普通的樣式類 -->
<!-- 兩個類的優先級是未定義的 -->
<!-- 建議:在使用外部樣式類的時,樣式需要通過 !important 添加權重 -->
<view class="extend-class box">通過外部樣式類修改組件的樣式</view>
?? custom09.wxss
.box {color: lightseagreen;
}
?? profile.wxml
<!-- 屬性是在 externalClasses 里面定義的元素 -->
<!-- 屬性值必須是一個類名 -->
<custom09 extend-class="my-class" />
?? profile.wxss
/* pages/index/index.wxss */.my-class {color: lightsalmon !important;
}
16. 完善復選框案例并總結自定義組件
總結自定義組件:
-
組件基本使用:數據、屬性、方法、插槽
-
組件樣式使用:組件樣式、注意事項、樣式隔離、外部樣式類
-
組件通信傳值:父往子傳值、子往父傳值、獲取組件實例
-
組件生命周期:組件的生命周期、組件所在頁面的生命周期、總結了小程序全部的生命周期
-
組件數據監聽器:observers
-
組件拓展:使用 Component 構造頁面、組件復用機制 behaviors 等
完善復選框案例
?? components/custom-checkbox/custom-checkbox.wxml
<!--components/custom-checkbox/custom-checkbox.wxml-->
<!-- <text>我是自定義組件</text> --><view class="custom-checkbox-container"><view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
+ <label class="custom-label"><checkbox class="custom-checkbox" checked="{{ isChecked }}" bindtap="updateChecked" /><view class="content"><!-- lable 和 子節點內容都進行了展示 --><!-- 要么展示 lable 要么展示 子節點內容 --><!-- 如果用戶傳遞了 lable 屬性,就展示 lable --><!-- 如果用戶沒有傳遞 lable 屬性,就展示 子節點內容 --><text wx:if="{{ label !== '' }}">{{ label }}</text><slot wx:else /></view>
+ </label></view>
</view>
?? components/custom-checkbox/custom-checkbox.wxss
+ .custom-checkbox-box .custom-label {display: flex;align-items: center;
}