微信小程序-組件化開發(下)

微信小程序組件化開發代碼實現 :
單從組件功能而言,wepy已經知足了小程序絕大部分的組件開發需求,堪稱完美。 
但若是權衡整個項目: 
開發前須要查看開發文檔,按照與小程序大相徑庭的寫法編寫小程序。對於不熟悉MVVM開發來講有必定的學習成本,並且對於不利於開發者熟悉小程序(就像一個前端開發的入門者就直接使用React.js開發,這樣很難熟悉諸如原生JS操做DOM的「相對底層」知識)。 
開發時也須要實時編譯以後才能預覽和調試,有必定的時間開銷。 
開發編譯後的代碼未能正常運行,究竟是編寫問題仍是編譯問題仍是框架問題?調試起來具備必定的複雜性。前端

因此wepy更適合大型小程序(當你有足夠理由使用它時),就像Vuex官方文檔中提到的那樣:若是您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 global event bus 就足夠您所需了。 
若是對於中小型的小程序,怎麼較好的實現組件化? 
wxss毫無異議地採用@import引用。 
而對於模板,因爲咱們使用include方式引用,因此只能和wepy同樣,經過命名的方式來隔離做用域。最簡單的方式莫過於給其增長組件名成作前綴。譬如:小程序

1.// src/components/tab.wxml
 2.<view class="tab">
 3.<view class="tab_item tab_message{{tabActive == 0 ? ' active' : ''}}" bindtap="tabChange(0)">
 4.<image class="icon" src="../images/message{{tabActive == 0 ? '_active' : ''}}.png">image>
 5.<text class="title">微信text>
 6.view>
 7....
 8.view>

而對於js能夠簡單封裝成對象,而後直接與頁面對象合併便可:微信小程序

1.// src/components/tab.js
 2.export default class {
 3.data: {
 4.tabActive: {
 5.twoWay: true
 6.}
 7.},
 8.change (idx, evt) {
 9.this.active = +idx;
 10.}
 11.}

不少人都會想到這樣調用:微信

1.// src/pages/index.wxml
 2.<include src="../components/tab.wxml"/>
 3....
 4.// src/pages/index.js
 5.import tab from '../components/tab.js'
 6.let page = {
 7....
 8.}
 9.Object.assign(page, tab)
 10.Page(page)

直接用Object.assign來實現最大的壞處就是父頁面沒法監聽組件事件,好比在例子中tab頁籤被點擊的時候,tab組件內部須要作樣式的變化,而對於父頁面也須要監聽這個事件來展示對應的內容。 
另外一種狀況,好比組件初始化也須要用到父頁面的data屬性的時候,那麼須要父頁面在初始化完成以後再調用組件自己的初始化函數。 
在onLoad中依次調用?這樣須要對每一個組件進行判斷和調用,太多垃圾代碼也容易出錯,顯然代碼不夠簡介和健壯。 
藉助MVVM框架的開發經驗,咱們能夠採用Vue.js中的mixin思路來解決這個問題。 
將組件和頁面對象進行混合。對於組件中的data屬性,咱們依然採起Object.assign的方式拷貝,因爲組件對象中咱們只要區分數據類型和事件函數,那麼能夠去掉data這一層。而對於事件咱們須要既觸發組件事件,也觸發頁面事件,那麼須要寫段代碼來實現。最後組件的定義和調用能夠修改成:app

1.// src/components/tab.js
 2.export default class {
 3.tabActive: {
 4.twoWay: true
 5.},
 6.change (idx, evt) {
 7.this.active = +idx;
 8.}
 9.}
 10.// src/pages/index.js
 11.import tab from '../components/tab.js'
 12.import {combine} from '../util.js'
 13.let page = {
 14.tabClick(event) {
 15....
 16.}
 17....
 18.}
 19.combine(page, tab)
 20.Page(page)

而對於combine函數只須要判斷數據類型而後執行對應的操做便可。框架

1.// util.js
 2./**
 3.* 組件對象與頁面對象融合
 4.* @param {Object} target 頁面對象
 5.* @param {Object} source 組件對象,支持不定參數
 6.* return {Object} 返回一個融合後的頁面對象
 7.*/
 8.let combine = (target, ...source) => {
 9.source.forEach(function(arg) {
 10.if('object' === typeof arg) {
 11.for(let p in arg) {
 12.if('object' === typeof arg[p]) {
 13.// 對於對象,直接採用 Object.assign
 14.target[p = target[p || {}
 15.Object.assign(target[p], arg[p])
 16.} else if('function' === typeof arg[p]) {
 17.// 函數進行融合,先調用組件事件,而後調用父頁面事件
 18.let fun = target[p ? target[p : function(){}
 19.delete target[p
 20.target[p = function() {
 21.arg[p].apply(this, arguments)
 22.fun.apply(this, arguments)
 23.}
 24.} else {
 25.// 基礎數據類型,直接覆蓋
 26.target[p = target[p || arg[p
 27.}
 28.}
 29.}
 30.})
 31.}
 32.export default {
 33.combine
 34.}

這種方案彷佛簡單明瞭地實現了組件化,可是有一個問題,那就是組件地複用。 
若是一個頁面中同時使用多個tab組件就會出現一些麻煩,由於相同組件沒有經過命名進行隔離,因此會有影響。 
解決方法只能經過修改組件自己或其它方式來支持了,不過好在大部分頁面中不會出現這樣的需求。xss

總結 
對於大型項目,學有餘力的開發者,能夠採用wepy這個很是優秀的小程序框架(既有構建工具,也有代碼)。 
對於中小型項目和初學者,採起混合的方式能知足組件化開發需求。函數

相關文章
相關標籤/搜索