微信小程序之自定义dialog组件

作者: Benny_lzb | 来源:发表于2018-04-12 20:06 被阅读306次

    由于项目开发需求,坑爹的小程序没有自定义dialog(类似饿了么组件那种)。于是百度了下思路,开发了一个。

    参数:
    title  标题
    cancelText  取消文本 (默认文本为取消)
    confirmText  确认文本(默认文本为确定)
    animated  是否动画 (默认为是)
    modalSize  模态框大小(默认md)
    animationOption  动画事件(默认300s)
    

    接下来分享下实现步骤吧...主要的概念就是想把自定义的部分通过<slot>插槽来接收。

    1. 创建好components组件且命好名字。 小tips:在微信开发工具内创建方便点它会自动帮你把相关文件配好。
      创建组件且命名
    2. 写好相关布局及样式。
      dialog.wxss
    /** 模态 **/
    .modal{
        position: fixed;
        top: 0rpx;
        left: 0rpx;
        right: 0rpx;
        bottom: 0rpx;
        width: 100%;
        height: 100%; 
        z-index: 100;
      }
      
      .modal-mask{
        position: absolute;
        width: 100%;
        height: 100%;
        z-index: 97;
        background-color: rgba(0,0,0,0.30);
      }
      
      
      .modal-layer-sm{
         width: 60%; 
         transform : translate3d(-50%,-50%,0);
         left : 50%;  
      } 
      
      .modal-layer-md{
         width: 80%; 
         transform : translate3d(-50%,-50%,0);
         left : 50%;    
      } 
      
      .modal-layer-full{
         width: 100%; 
         left: 0;  
      } 
      
      
      .modal-layer{
        position: absolute;
        background: transparent;
        top: 50%;    
        display: flex;
        flex-direction: column;
        z-index: 98;   
        box-shadow: 0 4rpx 14rpx rgba(0,0,0,.4); 
      }
      
      .modal-header{
        background: #fff;
        color:  #333;
        padding: 20rpx;
        font-size: 30rpx;
        text-align: center;
        border-top-left-radius: 10rpx;
        border-top-right-radius: 10rpx;  
     }
    
      .modal-body{
        flex:  1;  
        padding: 0 40px 40rpx;
        background: #ffffff;  
      }
    
      
    
    .modal-footer{
        background: #ffffff;
        flex-direction: row;
        display: flex;
        align-items: center;
        width: 100%;  
        border-top : 1rpx solid #eee;   
        border-bottom-left-radius: 10rpx;
        border-bottom-right-radius: 10rpx;  
    }
    
    .modal-close{
        color: #fff;
        font-size: 48rpx;
        position: absolute;
        right: 40rpx;
        top: 0;
        z-index: 98;
    }
    
    
    .btn{ 
      flex: 1; 
      text-align: center;   
      font-size: 30rpx;
      color:#666;
      padding:  19rpx 5rpx;
    }
    .btn:first-child{
        border-right: 1px solid #eee;
    }
    .btn-primary{
      color: #009887;   
    }
    

    dialog.wxml

    
    <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'>        
                <text>{{title}}</text>        
            </view>
    
            <!-- 内容区域 -->
            <view class='modal-body'>         
                <slot></slot>                          
            </view>
            <view class='modal-footer'>
                <text catchtap='_cancelModal' class='btn btn-default'>{{cancelText}}</text>
                <text catchtap='_confirmModal'  class='btn btn-primary'>{{confirmText}}</text>                         
            </view>
        </view>
    </view>
    
    1. dialog.js
    // common/component/modal.js
    Component({    
      
        /**
         * 组件的属性列表
         */
        properties: {
          title : {
            type : String,
            value : '这里是默认标题'
          },
          
          cancelText : {
            type: String,
            value: '取消'
          },
      
          confirmText : {
            type: String,
            value: '确定'
          },
          
          backdrop: {
            type: Boolean,
            value: true
          },
          
          animated : {
            type: Boolean,
            value: true
          },
    
          //模态框大小(sm md)
          modalSize : {
            type: String,
            value: "md"
          },
    
          //动画时间(默认300)
          animationOption : {
            type : Object,
            value  : {
              duration : 300 
            }
          },
    
         
        },
      
        /**
         * 组件的初始数据
         */
        data: {
          isShow:false,
          animation : ''
        },
       
      
        ready: function () {   
           this.animation = wx.createAnimation({
              duration: this.data.animationOption.duration,
              timingFunction: "linear",
              delay: 0
          }); 
        },
      
        /**
         * 组件的方法列表
         */
        methods: {
          //modal隐藏
          hideModal : function(e){  
            if(e){
              let type = e.currentTarget.dataset.type;
              if (type == 'mask' && !this.data.backdrop) {
                return;
              }   
            }                
            if (this.data.isShow) this._toggleModal();
          },
          
          //modal显示
          showModal: function(){
            if (!this.data.isShow) {
              this._toggleModal();         
            }
          },
    
          //切换modal的显示还是隐藏
          _toggleModal:function(){      
            if(!this.data.animated){
                this.setData({
                  isShow: !this.data.isShow
                })
            }
            else{
              let isShow = !this.data.isShow;
              this._executeAnimation(isShow);
            }
    
            
          },
          
          //根据需求执行动画
          _executeAnimation: function (isShow) {
            
              let animation = this.animation;
              if (isShow) {
      
                animation.opacity(0).step();
      
                this.setData({
                  animationData: animation.export(),
                  isShow: true
                })
      
                setTimeout(function () {
                  animation.opacity(1).step()
                  this.setData({
                    animationData: animation.export()
                  })
                }.bind(this), 50)
              }
              else {
                animation.opacity(0).step()
                this.setData({
                  animationData: animation.export()
                })
      
                setTimeout(function () {
                  this.setData({
                    isShow: isShow
                  })
                }.bind(this), this.data.animationOption.duration)
      
              }
      
      
            },
            //取消事件 向外部page 发送事件通知
            _cancelModal : function(){      
              this.hideModal();     
              this.triggerEvent("cancelEvent");
            },
    
            //确认事件
            _confirmModal : function(){     
              this.triggerEvent("confirmEvent");
            }
    
        }
      })
    

    核心都在这叻~注释都有哦。
    分析下怎么做到自定义弹层吧。


    slot图

    通过slot图所示,从图中可以知道通过slot插槽来接受modal-body里头自定义的代码。因为这里只需要一个插槽,所以插槽的名字可以省略,会自动配上。如果是需要多个slot的话,记得为插槽加上name="xxx"属性命名哦,对应的视图块通过 slot="xxx"接受对应的插槽数据。

    引用组件须知

    js部分
    需用在页面渲染的时候获取组件

      onReady: function () {
        this.Modal = this.selectComponent("#modal");
      },
    

    取消按钮以及确定按钮的回调事件

     _cancelEvent : function(){
        console.log("点击取消!");
      }
    
     _confirmEventFirst : function(){
        console.log("点击确定了!");  
        this.Modal.hideModal(); 
      }
    

    控制modal显示和隐藏

    this.Modal.showModal();//显示
    this.Modal.hideModal(); //隐藏
    

    好了展示下效果呗~


    效果图.png

    对了。标题这块以及按钮块都可以根据自己的需求再做调整哦。
    样式也可以调整。

    附git地址https://github.com/jerryli519/dialogComponent
    路过的小伙伴给下star哦~

    相关文章

      网友评论

      • 余暇_:如果是表单提交呢
        Benny_lzb:@余暇_ 是活的呀,在回调事件confirmEvent这,点击确定事件就会触发confirmEvent方法:yum:
        余暇_:@Jerry_lxb 确定按钮还是写活的好,小程序很多都需要button触发
        Benny_lzb:在dialog的回调事件 confirmEvent,获取表单内容然后提交
      • 施瓦辛格777:背景还能点击滑动是不是有点惊喜
      • 145c547d59d4:看完真使人茅塞顿开,困扰了一早上的问题终于解决了!感谢
      • muffinfeng:刚好解决了我的问题,顶

      本文标题:微信小程序之自定义dialog组件

      本文链接:https://www.haomeiwen.com/subject/woufkftx.html