組件化是web共郭、移動(dòng)開發(fā)的大趨勢(shì),一次開發(fā)多次使用糠馆,調(diào)用方便嘶伟,解耦性好。當(dāng)然在小程序開發(fā)是一個(gè)趨勢(shì)又碌。
官網(wǎng):https://mp.weixin.qq.com/debug/wxadoc/dev/component/
雖然說從自定義組件化有其官網(wǎng)介紹九昧,但是在開發(fā)過程中總是不盡如人意绊袋,踩過 幾次坑后還是決定自己基于基礎(chǔ)的原理按照極簡(jiǎn)的思想搞一下吧。
0x00 原理
本篇文章傾向于對(duì)于小程序或組件化原理有一定了解的群體铸鹰。說來很簡(jiǎn)單癌别,所謂的組件化包括幾個(gè)部分,類html,css,和js掉奄,這幾個(gè)部分分別控制元素规个,樣式,和代碼邏輯姓建,這幾個(gè)部分是要在被加載的地方分別把這三樣加入到容器里面去诞仓,可以說是重新為這個(gè)組件開辟了一塊內(nèi)存空間,重新在加載的地方渲染了樣式和元素速兔。簡(jiǎn)單點(diǎn)說是墅拭,在page中把模板里面的東西塞進(jìn)去,在一定的條件下顯示出來涣狗〉瘢或者說是把本來屬于本頁(yè)面的東西獨(dú)立開了放在了另外的文件里面。拆分出去的元素樣式和邏輯只是跟自己相關(guān)镀钓,加上一些數(shù)據(jù)傳遞和接收穗熬,就變成了組件。
0x01 插槽/模板加載
小程序里面有個(gè)template的東西丁溅,就是一個(gè)插槽唤蔗,在一次申明中
<template name="ShareData">
this is a template
</template>
即完成了包裝。里面的樣式寫法就是普通的方式窟赏,這就是模板的寫法
在需要用的時(shí)候,在wxml中引用它
<import src="ShareData"/>
0x01 CSS加載
樣式是在wxss里面設(shè)定的妓柜,在容器中添加
@import "../../componts/section/index";
@import "ShareData";
即可把樣式添加到對(duì)應(yīng)的page或其他組件中去。
0x02 JS加載與轉(zhuǎn)移
這個(gè)是重點(diǎn)涯穷,很多人并不知道組件化的根本原因是不知道組件的js屬性和方法是要添加到page里面去的棍掐。基于此其實(shí)也是兩句話的問題就可以完成導(dǎo)入方法和組件拷况。
做一個(gè)簡(jiǎn)單的例子作煌,實(shí)現(xiàn)sectioncontrol
let __outcomp__ = "__SegmentedControl__"
let SegmentedControl = {
data: {
radioValues: [
{'value': '男','selected': false},
{'value': '女','selected': true},
{'value': '保密','selected': false},
],
clazz: ['selected','last']
},
methods:{
indexChanged: function (e) {
// 點(diǎn)中的是組中第個(gè)元素
var index = e.target.dataset.index;
// 讀取原始的數(shù)組
var radioValues = this.data[__outcomp__].radioValues;
for (var i = 0; i < radioValues.length; i++) {
// 全部改為非選中
radioValues[i].selected = false;
// 當(dāng)前那個(gè)改為選中
radioValues[index].selected = true;
}
// 寫回?cái)?shù)據(jù)
this.setData({
[__outcomp__]: this.data[__outcomp__]
});
// clazz狀態(tài)
this.clazzStatus();
},
onLoad: function () {
// onLoad 比 onReady 更早調(diào)用,后者為選中時(shí)屏幕閃動(dòng)一下
this.clazzStatus();
},
clazzStatus: function () {
/* 此方法分別被加載時(shí)調(diào)用赚瘦,點(diǎn)擊某段時(shí)調(diào)用 */
// class樣式表如"selected last","selected"
var clazz = [];
// 參照數(shù)據(jù)源
var radioValues = this.data[__outcomp__].radioValues;
for (var i = 0; i < radioValues.length; i++) {
// 默認(rèn)為空串最疆,即普通按鈕
var cls = '';
// 高亮,追回selected
if (radioValues[i].selected) {
cls += 'selected ';
}
// 最后個(gè)元素, 追加last
if (i == radioValues.length - 1) {
cls += 'last ';
}
//去掉尾部空格
cls = cls.replace(/(\s*$)/g, '');
clazz[i] = cls;
}
// 寫回?cái)?shù)據(jù)
this.data[__outcomp__].clazz = clazz;
this.setData({
[__outcomp__]: this.data[__outcomp__]
});
}
},
};
function LoadSegmentedControl(fromData) {
let pages = getCurrentPages()
let curPage = pages[pages.length - 1]
Object.assign(curPage, SegmentedControl.methods);
curPage.setData({ [__outcomp__]: SegmentedControl.data });
console.log(curPage.data[__outcomp__])
return this;
}
module.exports = {
LoadSegmentedControl
};
重點(diǎn)看model.exports={LoadSegmentedControl},這其實(shí)是導(dǎo)出一個(gè)加載的方法的蚤告,這個(gè)方法用來把該組件中的data和method復(fù)制到當(dāng)前頁(yè)面中去。是的服爷,使用的是object.assign,另外data里面的數(shù)據(jù)是放到頁(yè)面data中的[outcomp]屬性值中杜恰。
0x03 數(shù)據(jù)傳遞
有幾種數(shù)據(jù)需要傳遞获诈,在wxml中如何傳遞,組件中的js如何更改里面的屬性心褐,組件間的數(shù)據(jù)如何傳遞舔涎。
還是基于模板的思想,從原理得知逗爹,組件中的標(biāo)簽和方法其實(shí)已經(jīng)加入到page中去了亡嫌,所以只需要去page樹中取值和方法即可。
如在加載模板的過程中如下傳遞數(shù)據(jù)
<template is="SegmentedControl" data='{{...SegmentedControl}}' />
這里有個(gè)技巧掘而,用...擴(kuò)展運(yùn)算符挟冠,把組件中的數(shù)據(jù)都一次性傳遞過來,并且傳遞之后的key和value都是同一個(gè)袍睡,這是es6的語法知染。
然而在js中的method需要改變屬性的方式則可以用
FSHeaderItemTap:function(e){
var index = e.currentTarget.dataset.idx;
console.log(e.currentTarget.dataset.idx);
this.data[outcomp].fsSelectIdx = e.currentTarget.dataset.idx;
this.setData({ [outcomp]: this.data[outcomp]})
if(index == 1){
LoadShareData();
}
},
可以看到,更改本組件中的屬性用的是this.data[outcomp]取值和賦值
0x04 應(yīng)用
組件與組件的嵌套斑胜,或者Page直接的使用都是用的這個(gè)原理控淡,在使用的過程中需要注意幾個(gè)規(guī)范,組件名要有前綴止潘,這樣方便查找方法和屬性掺炭。其他方式使用的命名空間就是這個(gè)作用吧。下面再來看看下面的界面凭戴,這高仿“阿拉丁小程序統(tǒng)計(jì)”的界面涧狮,有興趣的可以去看看如何實(shí)現(xiàn),結(jié)合本例原理簡(jiǎn)要分析一下簇宽。