微信小程序通用弹窗组件封装与动画实现

在微信小程序开发中,弹窗是常见的交互方式。官方并没有提供通用的 Dialog 组件,我们通常需要手写 view 并控制 show/hide 来实现,但这样会造成代码重复、维护不便。

本文将带你从零开始封装一个 通用的弹窗组件,支持以下特性:

  • 多种位置:顶部 / 中间 / 底部 / 左边 / 右边;

  • 动画效果:滑入 / 滑出、淡入 / 淡出;

  • 遮罩层:支持开启/关闭、点击关闭;

  • 插槽机制:弹窗内部内容可灵活替换;

  • 高复用性:页面只需简单调用即可。


一、组件文件结构

新建 components/popup/ 文件夹,结构如下:

html 复制代码
/components/popup/
  popup.wxml   # 组件结构
  popup.wxss   # 组件样式
  popup.js     # 组件逻辑
  popup.json   # 组件声明

二、popup.json

组件声明文件,标识这是一个自定义组件:

html 复制代码
{
  "component": true,
  "usingComponents": {}
}

三、popup.wxml

结构上分为两部分:

  1. 遮罩层(点击可关闭);

  2. 弹窗内容(支持插槽传入自定义内容)。

html 复制代码
<view wx:if="{{visible}}">
  <!-- 遮罩层 -->
  <view
    class="popup-mask"
    catchtap="onMaskTap"
    style="background-color: {{mask ? 'rgba(0,0,0,0.5)' : 'transparent'}}"
  ></view>
  <!-- 弹窗内容 -->
  <view class="popup-content {{position}} {{showAnim ? 'popup-show' : 'popup-hide'}}">
    <slot></slot>
  </view>
</view>
复制代码
说明:
  • visible 控制是否渲染;

  • mask 控制是否展示遮罩;

  • <slot> 插槽用于放置自定义内容。


四、popup.wxss

样式包括遮罩层、不同位置的初始样式,以及显示/隐藏时的过渡动画。

css 复制代码
/* 遮罩层 */
.popup-mask {
  position: fixed;
  z-index: 99;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
/* 弹窗基础样式 */
.popup-content {
  position: fixed;
  z-index: 100;
  background: #ffffff;
  border-radius: 12rpx;
  transition: all 0.3s ease;
  opacity: 0;
}
/* 位置样式 */
.top {
  top: 0;
  left: 0;
  width: 100%;
  transform: translateY(-100%);
}
.center {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.8);
  min-width: 60%;
}
.bottom {
  bottom: 0;
  left: 0;
  width: 100%;
  transform: translateY(100%);
}
.left {
  top: 0;
  left: 0;
  height: 100%;
  width: 70%;
  transform: translateX(-100%);
}
.right {
  top: 0;
  right: 0;
  height: 100%;
  width: 70%;
  transform: translateX(100%);
}
/* 显示动画 */
.popup-show.top,
.popup-show.bottom,
.popup-show.left,
.popup-show.right {
  transform: translate(0, 0);
  opacity: 1;
}
.popup-show.center {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}
/* 隐藏动画 */
.popup-hide.top {
  transform: translateY(-100%);
  opacity: 0;
}
.popup-hide.bottom {
  transform: translateY(100%);
  opacity: 0;
}
.popup-hide.left {
  transform: translateX(-100%);
  opacity: 0;
}
.popup-hide.right {
  transform: translateX(100%);
  opacity: 0;
}
.popup-hide.center {
  transform: translate(-50%, -50%) scale(0.8);
  opacity: 0;
}

说明:

  • 通过 transformopacity 实现平移、缩放和透明度过渡;

  • popup-show / popup-hide 类结合 transition 实现进场和退场动画。


五、popup.js

逻辑部分主要是 属性定义遮罩点击事件处理

javascript 复制代码
Component({
  properties: {
    // 是否显示弹窗
    visible: {
      type: Boolean,
      value: false
    },
    // 位置: top / center / bottom / left / right
    position: {
      type: String,
      value: 'center'
    },
    // 是否显示遮罩
    mask: {
      type: Boolean,
      value: true
    },
    // 点击遮罩是否关闭
    maskClosable: {
      type: Boolean,
      value: true
    }
  },
  data: {
    showAnim: false
  },
  observers: {
    visible(val) {
      if (val) {
        this.setData({ showAnim: true });
      } else {
        this.setData({ showAnim: false });
      }
    }
  },
  methods: {
    onMaskTap() {
      if (this.data.maskClosable) {
        this.triggerEvent('close'); // 抛出关闭事件
      }
    }
  }
});

说明:

  • visible 控制弹窗开关;

  • position 控制位置样式;

  • showAnim 用于切换显示/隐藏动画;

  • 点击遮罩层触发 close 事件,交由页面处理。


六、页面使用示例

1. 引用组件

在页面的 json 中引入:

html 复制代码
{
  "usingComponents": {
    "popup": "/components/popup/popup"
  }
}

2. 页面 WXML

html 复制代码
<view class="container">
  <button bindtap="openTop">顶部弹窗</button>
  <button bindtap="openCenter">中间弹窗</button>
  <button bindtap="openBottom">底部弹窗</button>
  <button bindtap="openLeft">左侧弹窗</button>
  <button bindtap="openRight">右侧弹窗</button>
  <!-- 顶部弹窗 -->
  <popup visible="{{showTop}}" position="top" bind:close="closeAll">
    <view class="popup-inner">这里是顶部弹窗内容</view>
  </popup>
  <!-- 中间弹窗 -->
  <popup visible="{{showCenter}}" position="center" bind:close="closeAll">
    <view class="popup-inner">这里是中间弹窗内容</view>
  </popup>
  <!-- 其他位置同理 -->
</view>

说明:

  • 通过 visible 控制弹窗显示;

  • position 控制位置;

  • 内部内容放在 <slot> 中,自由定义。

3. 页面 JS

javascript 复制代码
Page({
  data: {
    showTop: false,
    showCenter: false,
    showBottom: false,
    showLeft: false,
    showRight: false
  },
  openTop() {
    this.setData({ showTop: true });
  },
  openCenter() {
    this.setData({ showCenter: true });
  },
  openBottom() {
    this.setData({ showBottom: true });
  },
  openLeft() {
    this.setData({ showLeft: true });
  },
  openRight() {
    this.setData({ showRight: true });
  },
  closeAll() {
    this.setData({
      showTop: false,
      showCenter: false,
      showBottom: false,
      showLeft: false,
      showRight: false
    });
  }
});
复制代码
说明:
  • 每个按钮打开对应位置的弹窗;

  • closeAll 方法关闭所有弹窗。


七、总结

本文实现了一个 通用弹窗组件,支持:

  • 位置灵活:顶部、中间、底部、左、右五种方式;

  • 交互自然:支持遮罩层和点击遮罩关闭;

  • 动画平滑:滑入滑出、缩放淡入淡出效果;

  • 高度复用:通过插槽自定义内容,适配不同业务场景。

在实际项目中,你可以在此基础上扩展更多功能,例如:

  • 确认/取消按钮,做成标准的对话框;

  • 抽屉效果,用于侧边栏菜单;

  • 表单弹窗,用于收集用户输入。

通过封装组件,既能提高代码复用率,也能让交互体验更加统一和专业。 🚀

相关推荐
前端Hardy2 小时前
HTML&CSS: 在线电子签名工具
前端·javascript·canvas
biomooc3 小时前
D3.js 与数据可视化
开发语言·javascript·信息可视化
前端Hardy3 小时前
告别抽象!可视化动画带你学习算法——选择排序
前端·javascript·css
正义的大古3 小时前
OpenLayers地图交互 -- 章节八:平移交互详解
javascript·vue.js·交互·openlayers
LoveEate4 小时前
vue 在el-tabs动态添加添加table
javascript·vue.js·elementui
一颗努力的大土豆4 小时前
关于解决switch开关属性中active-value=“1“为数值形失败的问题
javascript·vue.js·elementui
Liu.7744 小时前
vue3 中实现 Element Plus 表格合并
javascript·vue.js·elementui
bitbitDown4 小时前
忍了一年多,我终于对i18n下手了
前端·javascript·架构
Hilaku4 小时前
前端的单元测试,大部分都是在自欺欺人
前端·javascript·单元测试