微信小程序组件化 快速实现可用模态窗

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 获得组件实例.

我们给<base-modal id="thridModal">这个组件创建一个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

一个基本模态窗口 就完成了, 满足基本业务使用 还有很多地方可以根据你们自身业务 进行 扩展.

本文原创 转载请注明署名和出处

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342