|
作者:u3xyz,來自授權(quán)地址
在做最近的小程序項(xiàng)目時(shí),需要使用到省市縣聯(lián)動(dòng)選擇器。瀏覽了一下小程組件,發(fā)現(xiàn)沒有直接提供這種組件,比較相近的picker組件也只支持selector|time|date。
當(dāng)然,我們可以使用view來模擬,但這樣開發(fā)量會(huì)比較大。再往下看,發(fā)現(xiàn)了picker-view + picker-view-column這對(duì)好基友,這不就是專門用來實(shí)現(xiàn)多列滾動(dòng)選擇的嗎?既然找到組件了,接下來就是如何實(shí)現(xiàn)了?
不急,我們還是先看一下組件最終效果:

使用類實(shí)現(xiàn)小程序組件
一些小程序組件通常會(huì)被設(shè)計(jì)成一個(gè)類。用代碼表示,大概是下面的樣子:
-
//componentXX.js
-
-
class ComponentXX() {
-
-
constructor(opts) {
-
this.$scope = opts.$scope;
-
},
-
-
methodA() {
-
// 使用this.$scope.setData()達(dá)到修改ViewModel的能力
-
}
-
}
-
-
export default ComponentXX;
使用時(shí),先引用定義,然后在onLoad時(shí)new一個(gè)實(shí)例,再調(diào)用實(shí)例相應(yīng)的方法,如:
-
import ComponentXX from 'path/to/conpoentxx/conpoentxx';
-
-
Page({
-
data: {
-
-
},
-
-
onLoad(opts) {
-
this.componentXX = new ComponentXX({
-
$scope: this,
-
opts: {}
-
});
-
},
-
-
bindTap() {
-
this.componentXX.doSomething();
-
}
-
});
項(xiàng)目里有幾個(gè)組件,也的確是這樣實(shí)現(xiàn)的。但這里有幾個(gè)問題: 1. 使用麻煩。除new之外,每次還得增加一些不必要的方法去調(diào)用組件實(shí)例相應(yīng)的方法,比如上面的bindTap方法 2. 因?yàn)閱栴}1,所以組件的封裝性很差 3. 同頁面多組件共存問題,是new多個(gè)組件嗎?
那么,還有沒有更簡(jiǎn)單,更好的組件封裝方式呢?
-
page({
-
onLoad(opts) {},
-
method() {}
-
});
其實(shí)我們觀察小程序頁面啟動(dòng)方法會(huì)發(fā)現(xiàn): 1. page函數(shù)需要傳入一個(gè)對(duì)象參數(shù),這里參數(shù)里面的特定函數(shù)onXXX(onLoad,onShow)會(huì)在頁面的特定生命同期被調(diào)用 2. 其它掛在對(duì)象參數(shù)上的方法或?qū)傩裕梢酝ㄟ^this訪問到。在wxml模板中,也可以直接調(diào)用 也就是說,我們擴(kuò)展對(duì)象參數(shù),就可以擴(kuò)展方法在.wxml模板中調(diào)用。基于此,有下面的組件封裝方式:
-
import ComponentXX from 'path/to/conpoentxx/conpoentxx';
-
-
Page(extend({
-
data: {
-
-
},
-
-
onLoad(opts) {
-
this.initComponentXXX(opts);
-
},
-
}, ComponentXX));
這種組件封裝方式,頁面注冊(cè)參數(shù)不需要多寫額外的方法??雌饋砀?jiǎn)潔,封裝性也更好。
實(shí)戰(zhàn):使用extend方式實(shí)現(xiàn)AddressPicker組件
-
import location from 'location.js'; // 數(shù)據(jù)文件。如果覺得數(shù)據(jù)文件太大,受小程序1M限制,可以通過cgi返回,然后存于緩存
-
-
const AddressPicker = {
-
/**
-
* 省市縣聯(lián)動(dòng)初始化個(gè)數(shù)。注意索引從0開始,例如apNumber = 2,則會(huì)有3個(gè)聯(lián)動(dòng)選擇控件
-
* @param apNumber
-
*/
-
initAddressPicker(apNumber = 0) {
-
-
// this 即頁面VM,可直接使用this.setData()方法
-
-
this.curApIndex = 0;
-
this.conf = [];
-
this.$address = location;
-
this.inited = false;
-
-
// TODO 因?yàn)椴荒芸刂剖》轁L動(dòng)到某個(gè)點(diǎn),所以不能在初始化時(shí)指定某個(gè)省市縣
-
this.$provinceList = this.getProvinceList();
-
-
while (apNumber-- >= 0) {
-
this.conf.push({
-
index: 0,
-
show: false,
-
prePid: 0,
-
pid: 0,
-
cid: 0,
-
tid: 0,
-
provinceList: this.$provinceList,
-
cityList: this.$address[0].children,
-
townyList: this.$address[0].children[0].children
-
});
-
}
-
-
// init ap VM
-
this.setData({
-
__ap: this.conf
-
});
-
-
setTimeout(() => {
-
this.inited = true;
-
}, 200);
-
},
-
-
getProvinceList() {
-
return this.$address.map(item => {
-
return {
-
label: item.label,
-
value: item.value
-
};
-
});
-
},
-
-
getCityList() {
-
try {
|