微信小程序自定義標簽組件component封裝、組件生命周期,組件通信
本文來說下小程序的自定義標簽組件封裝。
相比于vue,react的非路由組件,微信小程序的component組件要麻煩些,而且生命周期,數(shù)據(jù)接收傳遞方式也和路由組件不同!
假設(shè)你已經(jīng)創(chuàng)建好了微信小程序項目!
新建component組件
本文以封裝一個可用于關(guān)閉,添加,刪除的按鈕組件為例。
首先找到項目里面pages文件夾,鼠標右鍵pages文件夾,選擇新建目錄,輸入名字globalComponents,該文件夾用于存放component組件。鼠標右鍵globalComponents文件夾,選擇新建目錄,輸入名字closeAddReduceBtn,再右鍵closeAddReduceBtn文件夾,選擇新建Component,輸入名字closeAddReduceBtn。現(xiàn)在一個名為closeAddReduceBtn的component組件就創(chuàng)建好了。

component組件配置
創(chuàng)建好closeAddReduceBtn組件后,到pages下面的index文件夾,找到index.json文件,加上component組件配置,即usingComponents配置項。
index.json文件代碼:
{
"usingComponents": {
"Radios": "../../globalComponents/Radios/closeAddReduceBtn"
}
}
此行: "Radios": "../../globalComponents/closeAddReduceBtn/closeAddReduceBtn",closeAddReduceBtn是自定義的標簽名,后面是組件相對路徑
引入標簽組件
配置好后,到index.wxml文件中,寫上自定義標簽組件即可
component組件關(guān)鍵生命周期
這里只說關(guān)鍵,重要的生命周期
打開closeAddReduceBtn.js,我們可以看到,里面的內(nèi)容,不同玉路由組件,component組件是由Component構(gòu)造函數(shù)渲染的,onLoad,onShow什么的都沒了。
// globalComponents/closeAddReduceBtn/closeAddReduceBtn.js
Component({
/**
* 組件的屬性列表
*/
properties: {
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
* 組件的方法列表
*/
methods: {
}
})
properties 是屬性列表,通常用于接收父組件傳遞的值
data 用于存放組件本身的值
methods 用于存放自定義的函數(shù),類似vue的methods,在component里面,你直接像在路由組件里面寫方法是不能生效的,方法必須寫在methods里面。
組件加載執(zhí)行的函數(shù)是attached() {},需要我們手動加上,
組件頁面初始化完成執(zhí)行的函數(shù)是ready(){},手動給加上后,組件代碼
// globalComponents/closeAddReduceBtn/closeAddReduceBtn.js
Component({
/**
* 組件的屬性列表
*/
properties: {
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
},
/**
*組件加載執(zhí)行
*/
attached() {
},
/**
*組件初始化完成執(zhí)行
*/
ready(){
},
/**
* 組件的方法列表
*/
methods: {
}
})
closeAddReduceBtn組件頁面構(gòu)建
下面我們將closeAddReduceBtn組件頁面寫完
closeAddReduceBtn.wxml
<view
class="closeAddReduceBox"
style="width:{{boxSize}}rpx;height:{{boxSize}}rpx;background-color:{{boxBackgroundColor}};border-width:{{boxBorderWidth}}rpx; transform: rotate({{rotate}});border-color:{{boxBorderColor}}"
bindtap="clickBtn"
>
<text style="background-color:{{childBackgroundColor}};width:{{firstChildWidth}}rpx;height:{{firstChildHeight}}rpx"></text>
<text wx:if="{{!isSingle}}" style="background-color:{{childBackgroundColor}};width:{{lastChildWidth}}rpx;height:{{lastChildHeight}}rpx"></text>
</view>
closeAddReduceBtn.wxss
.closeAddReduceBox{
position: relative;
border-radius: 50%;
border-style: solid;
}
.closeAddReduceBox text{
position: absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%)
}
需要重點說的是closeAddReduceBtn.js
首先在properties中定義需要父組件傳遞的數(shù)據(jù),定義數(shù)據(jù)為對象,其中type屬性是定義接收的數(shù)據(jù)類型,value是默認值,如果需要默認值,可以在value里面定義。observer是定義傳遞值有變化時的監(jiān)聽函數(shù),不過注意observer的值是函數(shù)名字符串,然后需要到methods中定義該函數(shù)
屬性示例:
boxSize:{
type:Number,
value: 32,
observer:"getBoxSize"
},//按鈕尺寸
Component({
/**
* 組件的屬性列表
*/
properties: {
boxSize:{
type:Number,
value: 32,
observer:"getBoxSize"
},//按鈕尺寸
boxBackgroundColor:{
type:String
},//背景顏色
boxBorderWidth:{
type:Number
},//邊框?qū)挾? boxBorderColor:{
type: String
},//邊框顏色
rotate:{
type:String
},//選擇角度
childBackgroundColor:{
type:String,
value:'#ffffff'
},//按鈕里面橫線顏色,即加減圖標顏色
childSize:{
type:Number,
value:0
},//按鈕里面橫線尺寸,即加減圖標尺寸
isSingle:{
type:Boolean,
value:false
},//是否只有一條線,即刪除按鈕,或者減號按鈕
bold:{
type:Boolean,
value:false
}//是否加粗邊框
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
firstChildWidth:0,//第一根橫線寬度
firstChildHeight:0,//第一根橫線高度
lastChildWidth:0,//第二根橫線寬度
lastChildHeight:0,//第二根橫線高度
},
/**
*組件加載執(zhí)行
*/
attached() {
let { boxSize, boxBorderWidth, boxBorderColor, childSize, childHeight, rotate, onPressFun, bold } = this.data
if (boxSize !== 32) {
; !childSize && (childSize = (20 / 32) * boxSize)
// console.log(boxSize)
; !childHeight && (childHeight = (2 / 20) * childSize)
}
; !childSize && (childSize = 20)
; !childHeight && (childHeight = 2)
childHeight = bold ? (childHeight + 2) : childHeight
boxBorderColor && !boxBorderWidth && (boxBorderWidth = 2)
// console.log(boxBorderWidth)
this.setData({
firstChildWidth:childSize,
firstChildHeight: childHeight,
lastChildWidth: childHeight,
lastChildHeight: childSize,
boxBorderWidth
})
},
/**
* 組件的方法列表
*/
methods: {
//a按鈕點擊事件
clickBtn(){
//組件按鈕點擊事件,若需要向父組件傳遞數(shù)據(jù)或者讓父組件監(jiān)聽到相應(yīng)的操作,通過this.triggerEnent向父組件傳遞,三個參數(shù),第一個參數(shù)是父組件的監(jiān)聽事件名,第二個是傳遞給父組件的值,第三個參數(shù)是觸發(fā)事件的選項
let value='click'
let eventOption={
bubbles:false,// 默認false,事件是否冒泡
composed:false,// 默認false,事件是否可以穿越組件邊界,為false時,事件將只能在引用組件的節(jié)點樹上觸發(fā),不進入其他任何組件內(nèi)部
capturePhase:false,// 默認false,事件是否擁有捕獲階段
}
this.triggerEvent('event',value,eventOption)
},
//尺寸監(jiān)聽
getBoxSize(value){
//value是監(jiān)聽到的值
console.log(value)
}
}
})
父組件使用
接下來看父組件的使用
在index.wxml中
<closeAddReduceBtn class="closeAddReduceBtn" boxBackgroundColor="#999999" rotate="45deg" bindevent="delImg" data-index="{{index}}"/>
將需要的屬性直接傳遞即可。
特別注意的是bindevent,這是bind和組件事件名event的組合,event就是組件里面this.triggerEvent('event',value,eventOption)定義的event,假設(shè)我們在組件里面寫成this.triggerEvent('getBtn',value,eventOption),那么在父組件就要對應(yīng)寫成bingetBtn
下面看父級組件觸發(fā)的事件,component組件向父級組件傳遞的數(shù)據(jù),父級組件通過e.detail獲取
// 刪除圖片
delImg(e){
let {index}=e.currentTarget.dataset
let value=e.detail //value是component組件向父組件傳遞的數(shù)據(jù)
console.log(value)
let { showImgs}=this.data
showImgs.splice(index,1)
this.setData({
showImgs
})
},
關(guān)鍵生命周期函數(shù)的其他寫法以及其他類型生命周期
關(guān)鍵生命周期函數(shù)也可以用下面寫法
lifetimes: {
attached: function () {
// 在組件實例進入頁面節(jié)點樹時執(zhí)行
},
detached: function () {
// 在組件實例被從頁面節(jié)點樹移除時執(zhí)行
},
},
即將函數(shù)都寫在lifetimes中。
還有一些特殊的生命周期,它們并非與組件有很強的關(guān)聯(lián),但有時組件需要獲知,以便組件內(nèi)部處理。這樣的生命周期稱為“組件所在頁面的生命周期”,在 pageLifetimes 定義段中定義
pageLifetimes: {
show: function() {
// 頁面被展示
},
hide: function() {
// 頁面被隱藏
},
resize: function(size) {
// 頁面尺寸變化
}
}
在 behaviors 中也可以編寫生命周期方法,同時不會與其他 behaviors 中的同名生命周期相互覆蓋。但要注意,如果一個組件多次直接或間接引用同一個 behavior ,這個 behavior 中的生命周期函數(shù)在一個執(zhí)行時機內(nèi)只會執(zhí)行一次。
behaviors :{
created(){
}, //在組件實例剛剛被創(chuàng)建時執(zhí)行
attached(){
},//在組件實例進入頁面節(jié)點樹時執(zhí)行
ready(){
},//在組件在視圖層布局完成后執(zhí)行
moved(){
},//在組件實例被移動到節(jié)點樹另一個位置時執(zhí)行
detached(){
},//在組件實例被從頁面節(jié)點樹移除時執(zhí)行
error(){
},//Object Error 每當組件方法拋出錯誤時執(zhí)行
}
配置全局組件
有些組件,我們可能在很多頁面都會使用,因此希望只做一次配置即可,只需要在app.json中添加usingComponents配置即可
app.json
{
"pages": [
"pages/index/index",
"pages/hmongb/hmongb"
],
"window": {
"backgroundColor": "#633319",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#633319",
"navigationBarTitleText": "苗文hmongb",
"navigationBarTextStyle": "white"
},
"tabBar": {
"selectedColor": "#633319",
"color": "#898888",
"list": [
{
"iconPath": "./images/index-gray.png",
"selectedIconPath": "./images/index-active.png",
"text": "查詢",
"backgroundColor": "#ffffff",
"pagePath": "pages/index/index"
},
{
"iconPath": "./images/hmongb-gray.png",
"selectedIconPath": "./images/hmongb-active.png",
"text": "我的",
"backgroundColor": "#ffffff",
"pagePath": "pages/hmongb/hmongb"
}
]
},
"subpackages": [
{
"name": "hmongbPage",
"root": "hmongbPage",
"pages": [
"giveUsMsg/giveUsMsg"
]
}
],
"sitemapLocation": "sitemap.json",
"style": "v2",
"usingComponents": {
"Radios": "../../globalComponents/Radios/Radios",
"doubleTopBar": "../../globalComponents/doubleTopBar/doubleTopBar",
"leftScroll": "../../globalComponents/leftScroll/leftScroll",
"searchTopBar": "../../globalComponents/searchTopBar/searchTopBar",
"topTitleBar": "../../globalComponents/topTitleBar/topTitleBar"
}
}