組件化是web、移動開發的大趨勢,一次開發多次使用,調用方便,解耦性好。當然在小程序開發是一個趨勢。
官網:https://mp.weixin.qq.com/debug/wxadoc/dev/component/
雖然說從自定義組件化有其官網介紹,但是在開發過程中總是不盡如人意,踩過 幾次坑后還是決定自己基于基礎的原理按照極簡的思想搞一下吧。
0x00 原理
本篇文章傾向于對于小程序或組件化原理有一定了解的群體。說來很簡單,所謂的組件化包括幾個部分,類html,css,和js,這幾個部分分別控制元素,樣式,和代碼邏輯,這幾個部分是要在被加載的地方分別把這三樣加入到容器里面去,可以說是重新為這個組件開辟了一塊內存空間,重新在加載的地方渲染了樣式和元素。簡單點說是,在page中把模板里面的東西塞進去,在一定的條件下顯示出來。或者說是把本來屬于本頁面的東西獨立開了放在了另外的文件里面。拆分出去的元素樣式和邏輯只是跟自己相關,加上一些數據傳遞和接收,就變成了組件。
0x01 插槽/模板加載
小程序里面有個template的東西,就是一個插槽,在一次申明中
<template name="ShareData">
this is a template
</template>
即完成了包裝。里面的樣式寫法就是普通的方式,這就是模板的寫法
在需要用的時候,在wxml中引用它
<import src="ShareData"/>
0x01 CSS加載
樣式是在wxss里面設定的,在容器中添加
@import "../../componts/section/index";
@import "ShareData";
即可把樣式添加到對應的page或其他組件中去。
0x02 JS加載與轉移
這個是重點,很多人并不知道組件化的根本原因是不知道組件的js屬性和方法是要添加到page里面去的。基于此其實也是兩句話的問題就可以完成導入方法和組件。
做一個簡單的例子,實現sectioncontrol
let __outcomp__ = "__SegmentedControl__"
let SegmentedControl = {
data: {
radioValues: [
{'value': '男','selected': false},
{'value': '女','selected': true},
{'value': '保密','selected': false},
],
clazz: ['selected','last']
},
methods:{
indexChanged: function (e) {
// 點中的是組中第個元素
var index = e.target.dataset.index;
// 讀取原始的數組
var radioValues = this.data[__outcomp__].radioValues;
for (var i = 0; i < radioValues.length; i++) {
// 全部改為非選中
radioValues[i].selected = false;
// 當前那個改為選中
radioValues[index].selected = true;
}
// 寫回數據
this.setData({
[__outcomp__]: this.data[__outcomp__]
});
// clazz狀態
this.clazzStatus();
},
onLoad: function () {
// onLoad 比 onReady 更早調用,后者為選中時屏幕閃動一下
this.clazzStatus();
},
clazzStatus: function () {
/* 此方法分別被加載時調用,點擊某段時調用 */
// class樣式表如"selected last","selected"
var clazz = [];
// 參照數據源
var radioValues = this.data[__outcomp__].radioValues;
for (var i = 0; i < radioValues.length; i++) {
// 默認為空串,即普通按鈕
var cls = '';
// 高亮,追回selected
if (radioValues[i].selected) {
cls += 'selected ';
}
// 最后個元素, 追加last
if (i == radioValues.length - 1) {
cls += 'last ';
}
//去掉尾部空格
cls = cls.replace(/(\s*$)/g, '');
clazz[i] = cls;
}
// 寫回數據
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
};
重點看model.exports={LoadSegmentedControl},這其實是導出一個加載的方法的,這個方法用來把該組件中的data和method復制到當前頁面中去。是的,使用的是object.assign,另外data里面的數據是放到頁面data中的[outcomp]屬性值中。
0x03 數據傳遞
有幾種數據需要傳遞,在wxml中如何傳遞,組件中的js如何更改里面的屬性,組件間的數據如何傳遞。
還是基于模板的思想,從原理得知,組件中的標簽和方法其實已經加入到page中去了,所以只需要去page樹中取值和方法即可。
如在加載模板的過程中如下傳遞數據
<template is="SegmentedControl" data='{{...SegmentedControl}}' />
這里有個技巧,用...擴展運算符,把組件中的數據都一次性傳遞過來,并且傳遞之后的key和value都是同一個,這是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 應用
組件與組件的嵌套,或者Page直接的使用都是用的這個原理,在使用的過程中需要注意幾個規范,組件名要有前綴,這樣方便查找方法和屬性。其他方式使用的命名空間就是這個作用吧。下面再來看看下面的界面,這高仿“阿拉丁小程序統計”的界面,有興趣的可以去看看如何實現,結合本例原理簡要分析一下。