小程序自定義組件

微信小程序不支持自定義組件,只提供了一個非常受限制的模板功能,尤其缺乏了開發(fā)產(chǎn)品中最重要的幾個功能:
  • 模板內(nèi)的數(shù)據(jù)只能由當(dāng)前頁面?zhèn)鬟f,無法預(yù)先設(shè)置一些初始化數(shù)據(jù)以達(dá)到復(fù)用的目的;
  • 模板內(nèi)的數(shù)據(jù)變化無法通知到當(dāng)前頁面,也就是說模板不知道誰在使用它,只能在當(dāng)前頁面定義方法綁定在模板內(nèi)部的組件事件上來處理交互邏輯
  • 模板內(nèi)部無法預(yù)先設(shè)置一些內(nèi)部邏輯代碼。
這些局限性分分鐘叫人抓狂,這個模板功能只是實現(xiàn)了UI層復(fù)用的功能,所有的邏輯代碼都需要在頁面上重新寫一遍。開發(fā)和維護(hù)的效率一下子回到了解放前,再也沒法愉快地思考業(yè)務(wù)需求了,先把這個坑補(bǔ)補(bǔ)。 大路貌似走不通,只能另辟彎道,曲線救國了。 解決思路:所有的頁面都通過全局Page函數(shù)來定義,它提供了一個onLaunch的觸發(fā)事件,看來能在這里想想辦法。我們大致需要這樣的自定義組件或者說是模板:
 /*這是一個組件基類*/
module.exports = class BaseComp {        
    constructor({ key, page, data = {} }) { 
               this.key = key      
              this.page = page      
              this.data = data      ...    }    
/*當(dāng)組件內(nèi)部數(shù)據(jù)變化后,能在這里更新頁面*/    
update(){}    
/*當(dāng)頁面觸發(fā)事件時,組件也應(yīng)該能捕捉到*/ 
onLoad() {} onReady() {} onShow() {} onHide() {} onUnload() {}}

/*這是一個文本框組件*/
module.exports = class FormInput extends BaseComp { 
            constructor( { key, page, data }) {  
                 /*這里可以定義一些默認(rèn)數(shù)據(jù)*/               
                 data = Object.assign({               
                         type: 'text',                        
                         label: '',                        
                         placeholder: '',                        
                         value:'', 
                         ...                        
                         focus: false                
              }, data)                
             super( { key, page, data })    
    }        
      onfocus(e){...}       
      onblur(e){...}          
      onchange(e){...}
}
小程序的視圖(wxml)和js無法像webpack那樣打包在一起,所以只能利用現(xiàn)有的模板功能,把小程序原生組件組合成一個自定義組件。
<template name="formInput">    
        <view>        
              <label>{{label}}</label>       
              <input type="{{type}}" class="{{focus?' active':''}}"
                      placeholder-class="{{placeholderClass}}"            
                      placeholder="{{placeholder}}"            
                      value="{{value}}"            
                      data-key="{{key}}"            
                      data-index=""            
                      bindfocus="_EventProxy"            
                      bindblur="_EventProxy" />        
              <text>{{message}}</text>                
        </view>
</template> 
1. 寫個Page函數(shù),在App初始化之前中引入,把小程序的全局Page替換掉。在這個Page函數(shù)內(nèi)根據(jù)配置參數(shù)實例化自定義組件,把當(dāng)前頁面賦給組件的page屬性,并向組件傳入當(dāng)前頁面的'onLoad','onReady'等事件;
const Page = this.Page 
this.Page = function( config ) {
     if( config.components ) {        
          let onLoad = config.onLoad         
          config.onLoad = function() {            
                for( let key in config.components ) {                
                      let opts = config.components[ key ]                
                      opts.key = key                
                      opts.page = this                 
                      config.components[ key ] = new comp[ opts.is ]( opts ) 
                      config.components[ key ].onLoad( arguments ) 
                 }            
                if( onLoad ) { 
                       onLoad.call( this, arguments )           
                }       
         }
...... 
2. Page函數(shù)在當(dāng)前頁面上添加一個統(tǒng)一的事件代理(Proxy),自定義組件內(nèi)部的小程序原生組件上的事件全部指向這個代理方法,由這個事件代理根據(jù)事件對象判斷是由哪個自定義組件、自定義組件內(nèi)的哪個原生組件觸發(fā)的,觸發(fā)的是哪個事件,然后再調(diào)用自定義組件的處理方法去執(zhí)行內(nèi)部邏輯。
config._EventProxy = function( e ) {    
      let dset = e.currentTarget.dataset    
      let comp = config.components[ dset.key ]     
      /*        組件上定義的事件名必須為 on + event.type 
       data-index用來區(qū)分多個同名事件    */    
      let event = 'on' + e.type + dset.index   
      if( comp && comp[ event ] ) {        
          comp[ event ].call( comp, e )   
       }
}
最后再執(zhí)行小程序的Page函數(shù)
Page( config ) 
3. 自定義組件基類中實現(xiàn)了更新頁面數(shù)據(jù)的公共方法
update() {    
      let origin = this.page.data[this.key] || {}    
      let data = Object.assign({}, origin, this.data)     
      this.page.setData({       
           [this.key]: data    
      })
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 微信小程序自1月19號發(fā)布后,可謂是有人歡喜有人憂啊.曾經(jīng)對它一度抱有各種期待的前端工作者們在張總的一句句:...
    LinDaiDai_霖呆呆閱讀 6,270評論 6 11
  • 注意:目前自定義組件相關(guān)特性處于公測階段。如果需要使用相關(guān)特性,請確認(rèn)在項目選項中已勾選“預(yù)覽/上傳時使用新特性”...
    YU_YU_閱讀 3,246評論 0 5
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 原本就想能找個一個無人的地方寫一些不會有人看的文字。算是在忙碌迷茫的人生中對自己的一次救贖吧。 原...
    怎么都存在啊閱讀 162評論 0 0

友情鏈接更多精彩內(nèi)容