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


参数:

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


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

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>
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地址github.com/jerryli519/d
路过的小伙伴给下star哦~


本文转载:CSDN博客