微信小程序自定義組件原理探究

組件化是web、移動開發的大趨勢,一次開發多次使用,調用方便,解耦性好。當然在小程序開發是一個趨勢。

官網:https://mp.weixin.qq.com/debug/wxadoc/dev/component/

雖然說從自定義組件化有其官網介紹,但是在開發過程中總是不盡如人意,踩過 幾次坑后還是決定自己基于基礎的原理按照極簡的思想搞一下吧。

0x00 原理

本篇文章傾向于對于小程序或組件化原理有一定了解的群體。說來很簡單,所謂的組件化包括幾個部分,類html,css,和js,這幾個部分分別控制元素,樣式,和代碼邏輯,這幾個部分是要在被加載的地方分別把這三樣加入到容器里面去,可以說是重新為這個組件開辟了一塊內存空間,重新在加載的地方渲染了樣式和元素。簡單點說是,在page中把模板里面的東西塞進去,在一定的條件下顯示出來?;蛘哒f是把本來屬于本頁面的東西獨立開了放在了另外的文件里面。拆分出去的元素樣式和邏輯只是跟自己相關,加上一些數據傳遞和接收,就變成了組件。

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直接的使用都是用的這個原理,在使用的過程中需要注意幾個規范,組件名要有前綴,這樣方便查找方法和屬性。其他方式使用的命名空間就是這個作用吧。下面再來看看下面的界面,這高仿“阿拉丁小程序統計”的界面,有興趣的可以去看看如何實現,結合本例原理簡要分析一下。

image.png
極限水果,專注高端程序員技術與理財人生
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容