在某些場景,用到組件還是比較多的。例如,在頁面的底部有一個懸浮,懸浮分兩種,每種裏邊有四個按鈕,每個按鈕分爲登錄和沒登錄兩個狀態,點擊每個按鈕繪根據後臺傳的值的狀態不同分別請求不同的接口(當然了,有些處理完頁面也可能是跳轉,或者跳轉webview,或者reLaunch某個頁面......)。總之一句話,這個底部懸浮比較麻煩,考慮的場景比較多,然後呢,好多頁面都會用到,不用寫那麼多的重複代碼,寫好一個組件,大家都來調用,用的簡單,維護也簡單。
下邊我用一個簡單的場景來舉例,複雜場景原理相同,只不過是根據業務場景再做處理即可。
我的場景:頁面中的按鈕存在登錄和未登錄兩個狀態,組件中的按鈕也存在這兩個狀態,任何一處授權登錄過了,整個小程序的登錄狀態都會改變。此時若把父組件的登錄狀態改變,就要傳給子組件;子組件的登錄狀態改變,父組件也跟着變。但父子組件又相互獨立,此時就要通過某種方式來相互傳值。
1.組件('component/btn/btn’)
1.1.wxml
<view wx:if="{{isLogin}}" class='btn' catchtap='clickme'>子 組件的view</view>
<button wx:if="{{!isLogin}}" class='btn' open-type="getPhoneNumber" lang="zh_CN" bindgetphonenumber="getPhoneNumber">子 組件的button</button>
1.2.wxss
.btn{
width: 250rpx;
height: 50rpx;
line-height: 50rpx;
text-align: center;
background-color: orange;
font-size: 20rpx;
color: #fff;
margin-left: 0;
border-radius: 10rpx;
padding: 0 20rpx;
box-sizing: border-box;
margin: 20rpx 20rpx;
}
.btn::after{
border: 0;
}
1.3js
const app = getApp();
Component({
behaviors: [],
// 屬性定義(詳情參見下文)
properties: {
isLogin: {
type: Number,
value: 0,
}
},
data: {
}, // 私有數據,可用於模板渲染
lifetimes: {
// 生命週期函數,可以爲函數,或一個在methods段中定義的方法名
attached: function () {
// console.log(111111111111)
var that = this;
},
moved: function () {
// console.log(2222222222222)
},
detached: function () {
// console.log(3333333333333)
},
},
// 生命週期函數,可以爲函數,或一個在methods段中定義的方法名
attached: function () {
// console.log(4444444444444)
},
ready: function () {
// console.log(5555555555555555)
},
pageLifetimes: {
// 組件所在頁面的生命週期函數
show: function () {
// console.log(666666666666666666)
var that = this;
},
hide: function () {
// console.log(777777777)
},
resize: function () {
// console.log(88888888888888)
},
},
methods: {
clickme(e,aa='子請求接口'){
console.log(aa)
},
getPhoneNumber: function (e) {
var that = this;
if (e.detail.errMsg == "getPhoneNumber:ok") {
var param = {
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
logintype: 2
}
/**logintype:2時授權登錄**/
that.setData({
isLogin: true,
});
that.clickme(e,'子授權後請求接口')
var loginState = {
isLogin: 1
};
that.triggerEvent("triggerBottom", loginState);
} else {
wx.showToast({
title: '子授權失敗',
icon: 'none',
duration: 3000
});
}
},
},
});
1.4json
{
"component": true,
"usingComponents": {}
}
2.調用組件的文件
2.1wxml
<view wx:if="{{isLogin}}" class='btn'>父 組件的view</view>
<button wx:if="{{!isLogin}}" class='btn' open-type="getPhoneNumber" lang="zh_CN" bindgetphonenumber="getPhoneNumber">父 組件的button</button>
<fixbottom isLogin="{{isLogin}}" bind:triggerBottom="triggerBottom"></fixbottom>
2.2wxss
.btn{
width: 250rpx;
height: 50rpx;
line-height: 50rpx;
text-align: center;
background-color: orange;
font-size: 20rpx;
color: #fff;
margin-left: 0;
border-radius: 10rpx;
padding: 0 20rpx;
box-sizing: border-box;
margin: 20rpx 20rpx;
}
.btn::after{
border: 0;
}
2.3js
var that;
Page({
/**
* 頁面的初始數據
*/
data: {
isLogin: 0
},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function(options) {
that = this;
},
triggerBottom(e) {
var isLogin = e.detail.isLogin == 1 ? e.detail.isLogin : 0;
that.setData({
isLogin: isLogin
});
},
clickme(e, aa = '父請求接口') {
console.log(aa)
},
getPhoneNumber: function(e) {
var that = this;
if (e.detail.errMsg == "getPhoneNumber:ok") {
var param = {
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
logintype: 2
}
/**logintype:2時授權登錄**/
that.setData({
isLogin: true,
});
that.clickme(e, '父授權後請求接口')
} else {
wx.showToast({
title: '父授權失敗',
icon: 'none',
duration: 3000
});
}
},
})
2.4json
{
"usingComponents": {
"fixbottom": "/component/btn/btn"
}
}
3.說明
3.1小程序和vue類似,雙向數據綁定,組件其實就是一個標籤,在這個標籤上可以綁定一個數據,可以綁定一個事件,當然了,這個綁定的數據(或者事件)都須要遵從組件的規則。
3.2 父集向子集傳值,直接傳就好了,父集變子集跟着變。子集的值變,要想派發給父集,必須通過‘triggerEvent’來實現,派發出去。
3.3 現在的組件生命週期好像存在一些問題,第一次進入只執行了lifetimes裏的attached和ready兩個,pageLifetimes裏的show沒執行,看文檔的意思pageLifetimes應該是和頁面的聲明週期同步,但沒有(可能是個bug吧,嘻嘻)。但當頁面被back時會執行show生命週期(感覺還是有點不靠譜)。
3.4對於一進頁面和back回來都需要檢測登狀態(或者其他的狀態值的)建議在attached中執行一次接口請求,然後再show中也執行一次(如果這個值在緩存中,可以做一個判斷,如果爲真就不再請求,否則會請求),不然就會不靠譜,哈哈。
3.5在寫回調方法時,注意一下寫法,否則會出現意想不到的驚喜哦
dayin(aa='默認參數'){
console.log(aa)
},
dioyong(cb) {
typeof cb == "function" && cb();
},
right(cb) {
var that = this;
this.dioyong(function(){
that.dayin('this is right')
});
},
wrong() {
var that = this;
this.dioyong(that.dayin('this is wrong'))
}
例如上邊的right方法和wrong方法,看着好像都對,你自己在本地調用運行一下。
直接寫結論了,right方法確確實實是當回調函數來執行的,wrong方法並不是,尤其是在接口調用,涉及接口調用順序的情況就會出錯。wrong裏的調用,加了括號,相當於函數調用語句直接執行了,就沒走 typeof cb == "function" && cb() 。而right確實是一個function(哈哈,應該是這個原因吧)。