微信小程序 自定义封装模态框modal组件

本文介绍了一种自定义小程序模态框组件的实现方法,包括设计思路、代码实现及页面引用过程,解决了小程序框架限制下的动画和平滑过渡问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小程序的设计没法用第三方框架包,而他自己也没有好用的模态框,只有几个基本弹出框,无法满足业务需求,所以决定自己封装一个模态框组件。

此组件设计了从上下左右四个方向弹出,目前只是测试版本:

1.设计思路

传统的模态框就是有个div然后用平滑过渡动画使它弹出。

首先需要考虑动画的选择,由于小程序中js无法控制dom,也就无法控制css,所以用@frame的方式做动画不可取,因为无法给css中传值;

然后考虑到小程序自带的用js控制动画,结果里面全是坑,非常不好用,谁用是知道。

结果只能是用css中自带动画一条路了。

利用transiton和transform:translate解决平滑过渡问题

然后就是高度和模态框的位置可以通过参数控制了

新建出modal组件(新建component)

2.代码实现

我尝试先粘代码再解释

modal.wxml:

<!--遮罩层-->
<view class='mask' wx:if="{{showModalStatus}}" bindtap='closeModal' style="opacity:{{opacity}}"></view>
<!--弹出模态框-->
<view class='mymodal' wx:if="{{showModalStatus}}" 
style='width:{{width}};height:{{height}};top:{{top}};bottom:{{bottom}};left:{{left}};right:{{right}}'>
  <!-- 模态框title -->
  <view class='mymodal-title'> 
    <slot name="modalName"></slot>
    <text class='fa fa-close fa-lg' style='color:#aaa;font-style:normal' bindtap='closeModal'></text>
  </view>
  <!-- 模态框内容 -->
  <view class='mymodal-content' style='height:calc({{height}} - 80px)'>
    <slot name="modalContent"></slot>
  </view>
</view>

因为小程序中想用js控制css只有在wxml中添加行内样式接收js参数一种方法,所以我把可变样式都用{{}}方式接收。

showModalStatus控制模态框是否显示,点击x号或者遮罩层模态框消失

这个x号按钮我用了fontawesome字体,由于组件中不能引用外部css,所以需要在引用modal的页面加上字体css,这个字体转css有些麻烦,可以直接用字母x代替他。

组件中一般都需要有slot,用于页面引用时添加自定义标签用的,我这里加了一个slot用于modal名字,一个slot用于modal内容,

多个slot用name区分

modal.xwss:

/*遮罩层*/
.mask{
  position: fixed;
  width:100%;height:100%;
  background:rgba(0,0,0,0.5);
  top:0;left:0;
  z-index: 10;transition: all 300ms ease-out;
}
/*弹出模态框*/
.mymodal{
  width:100%;
  position: fixed;z-index: 20;
  background:white;height:460px;
  border-radius: 10rpx;transition: all 300ms ease-out;
}
.mymodal .mymodal-title{
  font-size:30rpx;height:50px;line-height:50px;
  border-bottom:1px solid #ddd;
  color:#666;padding:0 20px;
  display: flex;justify-content:space-between;
  align-items: center
}
.mymodal .mymodal-content{
  padding:15px;height:320px;overflow: scroll;
}

css就是简单的样式,注意给modal和mask加个transition就行了,动画效果都是动态改变modal的top,left等值,有transition就会有平滑过渡效果

modal.js:

Component({
  /**
   * 组件的属性列表(共有数据)
   */
  properties: {
    //modal出现动画类型
    fadeStyle: {
      type: String,
      value: '',
      observer(newVal, oldVal, changedPath) {
      // 属性被改变时执行的函数(可选),通常 newVal 就是新设置的数据, oldVal 是旧数        
        if (newVal == "slideUp") {//从下向上滑出
          this.setData({
            bottom: '-' + this.properties.height,
          })
        } else if (newVal == "slideDown") {//从上向下滑出
          this.setData({
            top: '-' + this.properties.height,
          })
        } else if (newVal == "slideRight") {//从左向右滑出
          this.setData({
            left: '-' + this.properties.width
          })
        } else if (newVal == "slideLeft") {//从右向左滑出
          this.setData({
            right: '-' + this.properties.width
          })
        }
      }
    },
    width: {
      type: String,
      value: '100%',
    },
    height: {
      type: String,
      value: '',
    },
    top: {
      type: String,
      value: ''
    },
    bottom: {
      type: String,
      value: ''
    },
    left: {
      type: String,
      value: ''
    },
    right: {
      type: String,
      value: ''
    },
    opacity: {
      type: String,
      value: '0'
    },
  },

  /**
   * 组件的初始数据(私有数据)
   */
  data: {
    //控制模态框打开关闭参数
    showModalStatus: false
  },
  options: {
    addGlobalClass: true, //使其可以使用全局样式
    multipleSlots: true //使其可以使用多个slot,用name区分
  },
  /**
   * 组件的方法列表
   */
  methods: {
    //打开模态框
    showModal: function(event) {
      this.setData({
        showModalStatus: true
      })
      //需要等模态框出现再执行动画,否则无动画效果
      setTimeout(function() {
        if (this.properties.fadeStyle == "slideUp") {
          this.setData({
            bottom: 0,
            opacity: 1
          })
        } else if (this.properties.fadeStyle == "slideDown") {
          this.setData({
            top: 0,
            opacity: 1
          })
        } else if (this.properties.fadeStyle == "slideRight") {
          this.setData({
            left: 0,
            opacity: 1
          })
        } else if (this.properties.fadeStyle == "slideLeft") {
          this.setData({
            right: 0,
            opacity: 1
          })
        }

      }.bind(this), 100)
    },
    //关闭模态框
    closeModal: function() {
      //判断动画样式
      if (this.properties.fadeStyle == "slideUp") {
        this.setData({
          bottom: '-' + this.properties.height,
          opacity: 0
        })
      } else if (this.properties.fadeStyle == "slideDown") {
        this.setData({
          top: '-' + this.properties.height,
          opacity: 0
        })
      } else if (this.properties.fadeStyle == "slideRight") {
        this.setData({
          left: '-' + this.properties.width,
          opacity: 0
        })
      } else if (this.properties.fadeStyle == "slideLeft") {
        this.setData({
          right: '-' + this.properties.width,
          opacity: 0
        })
      }
      //等关闭动画完毕后再移除模态框和遮罩
      setTimeout(function() {        
        this.setData({
          showModalStatus: false
        })
      }.bind(this), 400)
    }
  }
})

组件component中有properties用于存放共有信息和data用于存放私有信息。由于模态框大小和位置采用可控制设计,所以在properties中设置模态框位置参数用于接收引用页面传来的参数。

fadeStyle为动画样式,通过observer监听fadeStyle的变化,判断不同的动画类型而采取不同的方式策略。

我这样设计width和height可以传px也可以传百分数。

然后执行弹出和关闭时都控制一下动画就行了。

值得一提的是当showModalStatus为true时,理论上模态框出现然后执行动画,但貌似modal的出现需要点时间,最好定时100ms后再执行动画,否则会出现动画不稳定

modal.json

{
  "component": true,
  "usingComponents": {}
}

作为一个组件,需要在json中写上component:true才行

3.页面引用

test.json

{
  "usingComponents": {
    "my-modal": "/assets/components/modal/modal"
  }
}

由于json文件比较重要,我放在前面

在需要引用组件的页面的json中,需要写上usingComponents,my-modal为自己起得名字,你起啥名字引用的时候就用啥名字,后面写上组件的路径即可 

test.wxml:

<button bindtap='showModal'>打开模态框</button>
<!--向上弹出-->
<my-modal id="modal" fadeStyle="slideUp"  height="460px" >
  <view slot="modalName">这是个自定义模态框</view>
  <view slot="modalContent"></view>
</my-modal>

my-modal就是json中自己起得名字

注意写上id,js中调用组件方法需要用到这个id寻找组件

然后就是我们自定义的参数,fadeStyle对应modal.js 中properties中的fadeStyle,要注意在这里设置的参数properties中都是可以接收到的,并且会触发oberver监听。width,height,top等都可以设置

<button bindtap='showModal'>打开模态框</button>
<!--向下弹出-->
<my-modal id="modal" fadeStyle="slideDown"  height="460px" >
  <view slot="modalName">这是个自定义模态框</view>
  <view slot="modalContent"></view>
</my-modal>
<button bindtap='showModal'>打开模态框</button>
<!--向右弹出-->
<my-modal id="modal" fadeStyle="slideRight"  height="100%" width="80%" top="0">
  <view slot="modalName">这是个自定义模态框</view>
  <view slot="modalContent"></view>
</my-modal>
<button bindtap='showModal'>打开模态框</button>
<!--向左弹出-->
<my-modal id="modal" fadeStyle="slideLeft"  height="100%" width="80%" top="0" >
  <view slot="modalName">这是个自定义模态框</view>
  <view slot="modalContent"></view>
</my-modal>

test.js

Page({
  data: {

  },
  onLoad: function (options) {
    this.modal = this.selectComponent("#modal");//通过给组件所起的id调用组件
  },
  showModal:function(){
    this.modal.showModal()  //调用组件中打开模态框方法
  }  
})

onload是用前面设置的id把组件调出来加到this中,注意只能是id

然后点击按钮时调用组件打开模态框方法即可

 

这只是个demo,实战中将自己的内容放到slot中,例如:

<my-modal id="modal" fadeStyle="slideUp"  height="460px" >
  <view slot="modalName">这是个自定义模态框</view>
  <view slot="modalContent">
    <view class='companyBtns'>
      <button class='{{company==1?"active":""}}' bindtap='getPackageListByComany' data-i='1'>
        <image src='/assets/images/ff.png' />
        <text>移动套餐</text>
      </button>
      <button bindtap='getPackageListByComany' data-i='2' class='{{company==2?"active":""}}'>
        <image src='/assets/images/vv.png' />
        <text>联通套餐</text>
      </button>
      <button bindtap='getPackageListByComany' data-i='3' class='{{company==3?"active":""}}'>
        <image src='/assets/images/bbf.png' />
        <text>电信套餐</text>
      </button>
    </view>
    <view class='packageListContent'>
      <view class='packageListLine'>
        <text class='p1 '>套餐名称</text>
        <text class='p2'>资费,分钟,流量</text>
        <text class='p3'>人气</text>
      </view>
      <view class='packageListLine' wx:for="{{packageData}}" wx:for-item="data" bindtap="pickIt" data-i="{{index}}">
        <text class='p1'>{{data.PACKAGE_NAME}}</text>
        <text class='p2'>{{data.FEE}},{{data.DURATION}},{{data.FLOW}}</text>
        <text class='p3'>{{data.POPU_VALUE}}</text>
      </view>
    </view>
  </view>
</my-modal>

4.总结

犹豫刚学小程序,好多地方都考虑不周到,这里只是总结一下自己的思路,起码自己目前可以使用

提供个下载吧,不想看废话的可以直接下载看看效果

下载地址:https://download.youkuaiyun.com/download/lianzhang861/10980422

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆趣编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值