微信小程式元件化 快速實現可用模態窗

sherlock221b發表於2019-02-16

image.png

縱觀現代前端框架中(不論ng react vue ) 基本四架馬車 宣告式渲染 路由 元件化 狀態管理。 反觀小程式開發環境 缺失蠻多特性的 好在 11月初微信團隊,釋出了官方的component 化方案, 我們基本上可以告別現有的hack辦法去實現 component 化。

hack方式

使用template實現元件化 https://zhuanlan.zhihu.com/p/26785726 使用include元件化 這個簡單說下 include 元件wxml 和樣式檔案到 page 然後 ,import 元件的js檔案 通過合併方式將元件data method 合併到page 對於data,直接採用 Object.assign method 進行融合,先呼叫元件事件,然後呼叫父頁面事件.

以上方案核心: 將元件內定義的 data 和 method 合併到page中去 實現元件化, 本質上都在同一個作用域下 元件作用域沒有隔離 難免會出現 命名衝突 覆蓋.

實現一個元件

方便快速理解,下面使用官方元件化方案 實現一個模態彈窗 easyModal.

請結合原始碼看 https://github.com/sherlock221/wx-easyModal 如果覺得不錯請點個star

閱讀前 請先讀通官方自定義元件文件 https://mp.weixin.qq.com/debug/wxadoc/dev/framework/custom-component/

元件分析

首先分成2個小元件 來實現這個模態彈窗 基本模態彈窗 和 增強型模態彈窗

基本模態彈窗 具備

image.png

1.顯示/隱藏 2.backdrop
3.過度動畫
4.自定義頭尾 這幾部分基礎功能

增強型模態彈窗 具備

image.png

1.基礎模態彈窗功能 2.自定義內容區域 3.title自定義 4.確定取消按鈕自定義

基本模態窗

image.png

首先在base資料夾下直接右鍵建立component -> baseModal 在baseModal.js中建立元件所需要props 這些屬性來自父元件或 外層page 中的資料,

Component({    

  options : {
    multipleSlots: true 
  },
  /**
   * 元件的屬性列表
   */
  properties: {

    backdrop: {
      type: Boolean,
      value: true
    },

    animated : {
      type: Boolean,
      value: true
    },
    
    modalSize : {
      type: String,
      value: "md"
    },
  
    animationOption : {
      type : Object,
      value  : {
        duration : 300 
      }
    }
   
  },
}
複製程式碼

下來建立 data,isShow控制 彈窗顯示和隱藏 animation則是彈窗動畫函式.

/**
   * 元件的初始資料
   */
  data: {
    isShow : false,
    animation : ''
  },
複製程式碼

在生命週期函式 ready中初始化animation

ready: function () {   
     this.animation = wx.createAnimation({
       duration: this.data.animationOption.duration,
      timingFunction: "linear",
      delay: 0
    }); 
  },
複製程式碼

元件有2個public方法 show hide 方法, private 有執行動畫 和 切換顯隱的方法

methods: {
      hideModal : function(e){  
        if(e){
          let type = e.currentTarget.dataset.type;
          if (type == 'mask' && !this.data.backdrop) {
            return;
          }   
        }                
        if (this.data.isShow) this._toggleModal();
      },

      showModal : function(){
        if (!this.data.isShow) {
          this._toggleModal();         
        }
      },

      _toggleModal : function(){      
        if(!this.data.animated){
            this.setData({
              isShow: !this.data.isShow
            })
        }
        else{
          let isShow = !this.data.isShow;
          this._executeAnimation(isShow);
        }

        
      },

      _executeAnimation: function (isShow) {
        ......
      }

  }

複製程式碼

可以通過animated屬性來判斷 元件是否需要呼叫_executeAnimation 來執行動畫顯示

頁面結構

<view  animation="{{animationData}}"  hidden="{{!isShow}}"  class='modal'>

     <view  data-type="mask"  catchtap='hideModal' class='modal-mask' ></view>
  
      <view  class='modal-layer  modal-layer-radius {{modalSize == "sm" ? " modal-layer-sm" : " modal-layer-md" }} ' >

        <!-- 頭部 -->
          <view class='modal-header'>        
              <slot name="header"></slot>             
          </view>

          <!-- 內容區域 -->
          <view class='modal-body'>         
               <slot name="body"></slot>                          
          </view>

          <view class='modal-footer'>
               <slot name="footer"></slot>                     
          </view>
      </view>
  </view>
複製程式碼

slot 節點,用於承載元件使用者提供的wxml結構。 預設情況下,一個元件的wxml中只能有一個slot。需要使用多slot時,記得開啟配置

options : {
    multipleSlots: true 
  },
複製程式碼

下來建立樣式wxss 具體可以看github 檔案這就不貼

/** 模態 **/
.modal{
  position: fixed;
  top: 0rpx;
  left: 0rpx;
  right: 0rpx;
  bottom: 0rpx;
  width: 100%;
  height: 100%; 
  z-index: 100;
}
..............
複製程式碼

需要注意 元件wxss檔案 具備 隔離性的 你在page 中定義的class , 在app.wxss 中定義的class 都無法再元件中使用,如果真有一些需要複用到的樣式 可以抽取成一個wxss 通過import 匯入 元件的wxss

@import "../../style/font.wxss";
複製程式碼

這樣會增加元件和業務的耦合度 公共元件不建議使用

接下來可以在業務介面中去使用

<base-modal id="thridModal">
  <view slot="header" class='modal-header'>
        頭部
    </view>
     <view slot="body" class='modal-body'>
        中間
    </view>
 
    <view slot="footer" class='modal-footer'>
         尾部      
    </view>

</base-modal>
複製程式碼

別忘了在業務頁面的json中引入元件

{ 
    "usingComponents": {     
      "base-modal": "/component/easyModal/base/baseModal"
    }
  
}
複製程式碼

還記得我們上面baseModal 有兩個public方法 怎麼樣去呼叫呢 這裡介紹下

Component 的一個例項方法 selectComponent 通過它 可以找到子元件例項 這個有點像是 jq 選擇器 通過selector去尋找dom(但是不是dom是js物件) 不過它更像是 react 或 vue ref this.$refs.xxx 獲得元件例項.

我們給這個元件建立一個id 通過id選擇器就可以找到base-modal的例項 在ready中找到modal例項

onReady: function () {     
    this.thridModal = this.selectComponent("#thridModal");
  },
複製程式碼

然後就可以呼叫例項的public的方法.

this.thridModal.showModal();
this.thridModal.hideModal();
複製程式碼

增強模態窗

增強模態窗是基於baseModal的.

{
  "component": true,
  "usingComponents": {
    "base-modal" : "../base/baseModal"
  }
}
複製程式碼

注意 增強模態視窗 需要包含 基本模態視窗 json中引用才能使用

<base-modal id="baseModal"   modalSize="{{modalSize}}"  animated="{{animated}}"  backdrop="{{backdrop}}">
    <view slot="header" class='modal-header'>
        <text>{{title}}</text>
    </view>

     <view slot="body" class='modal-body'>
        <slot></slot>
    </view>
 
    <view slot="footer" class='modal-footer'>
         <text catchtap='_cancelModal' class='btn btn-default'>{{cancelText}}</text>
         <text catchtap='_confirmModal'  class='btn btn-primary'>{{confirmText}}</text>      
    </view>

</base-modal>
複製程式碼

說下event部分 確定 取消按鈕是需要 向外部page 傳送事件通知的其進行業務操作的

 //cancel
    _cancelModal : function(){      
      this.hide();     
      this.triggerEvent("cancelEvent");
    },

    //success
    _confirmModal : function(){     
      this.triggerEvent("confirmEvent");
    }
複製程式碼

通過triggerEvent觸發事件 這點和官網文件沒有區別.

業務Page介面:

<easy-modal  
      id="easyModal" 
      title="這個是標題 01"   
      bind:cancelEvent="_cancelEvent"  
      bind:confirmEvent="_confirmEventFirst"  
      >  <view class='modal-content'>
             <text> 這是內容部分 01 </text>     
             <text> 這是內容部分 01 </text>     
             <text> 這是內容部分 01 </text>                                             
      </view>    

</easy-modal>
複製程式碼

image.png

一個基本模態視窗 就完成了, 滿足基本業務使用 還有很多地方可以根據你們自身業務 進行 擴充套件.

本文原創 轉載請註明署名和出處

相關文章