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

微信小程序自定义Dialog组件实现
本文详细介绍了如何在微信小程序中创建一个自定义的Dialog组件,包括组件的设计思路、结构布局、样式设置以及交互逻辑的实现。通过该组件,开发者可以更灵活地控制对话框的显示效果和功能,提升用户体验。

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


```
参数:
title  标题
cancelText  取消文本 (默认文本为取消)
confirmText  确认文本(默认文本为确定)
animated  是否动画 (默认为是)
modalSize  模态框大小(默认md)
animationOption  动画事件(默认300s)
```
接下来分享下实现步骤吧...主要的概念就是想把自定义的部分通过<slot>插槽来接收。
1. 创建好components组件且命好名字。 *小tips:在微信开发工具内创建方便点它会自动帮你把相关文件配好。*
![创建组件且命名](https://upload-images.jianshu.io/upload_images/4309138-40fe80f9262ed467.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
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>
   ```
3. 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图](https://upload-images.jianshu.io/upload_images/4309138-dc002412f90e691b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
通过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](https://upload-images.jianshu.io/upload_images/4309138-e7586a3ca91bb191.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


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


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值