当前位置: 首页 > news >正文

uniapp定义一个简单的全局弹窗组件

兼容H5、微信小程序、安卓APP

(1)封装成组件

dialog.js

export default { /* 链接处理 */ getLink(params){ let url = "/components/dialog/dialog"; if(params){ let paramStr = ""; for(let name in params){ paramStr+=`&${name}=${params[name]}` } if(paramStr){ url +=`?${paramStr.substr(1)}` } } return url; }, /* APP全局弹窗 */ dialog(params={},callback){ const store = getApp().globalData.store store.commit('setAppDialogShow', true) uni.navigateTo({ url:this.getLink(params), success(e) { uni.$off("wujw_common_dialog"); uni.$on("wujw_common_dialog",(type)=>{ callback&&callback(type) }) } }) }, /*弹出提示弹窗 */ alert(data={},callback,close){ let params = {type:"alert",isCloseBtn:'0',isMaskClose:'0',...data}; this.dialog(params,(type)=>{ if("confirm"==type){ callback&&callback() }else { close&&close() } }) }, /*确认提示框弹窗 */ confirm(data={},confirm,cancel,close){ let params = {type:"confirm",isCloseBtn:'0',isMaskClose:'0',...data}; this.dialog(params,(type)=>{ if("confirm"==type){ confirm&&confirm() }else if("cancel"==type){ cancel&&cancel() }else if("close"==type){ close&&close() } }) }, }

dialog.vue

<template> <view @click="itemClick('mask')" class="mask-content"> <view class="dialog-content" @click.stop=""> <view class="head-content " v-if="info.title" :style="info.content?'':'min-height:90rpx;padding:30rpx'"> <text>{{info.title}}</text> </view> <scroll-view class="main-content" scroll-y v-if="info.content"> <view class="info-content"> <text>{{info.content}}</text> </view> </scroll-view> <view class="foot-content alert" v-if="'alert'==info.type"> <view class="btn active" @click.stop="itemClick('confirm')"> {{info.confirmText}} </view> </view> <view class="foot-content confirm" v-if="'confirm'==info.type"> <view class="btn cancel" @click="itemClick('cancel')"> {{info.cancelText}} </view> <view class="btn active" @click.stop="itemClick('confirm')"> {{info.confirmText}} </view> </view> </view> </view> </template> <script> export default { data() { return { info: { type: "alert", //alert:单按钮,confirm:双按钮 title: "", // content: "", cancelText: "取消", confirmText: "确定", isMaskClose: "1", //1点击遮罩层关闭弹窗 } } }, onLoad(info = {}) { this.info = { ...this.info, ...info }; }, methods: { itemClick(type) { if (type == "mask" && this.info.isMaskClose != '1') { return; } uni.navigateBack() uni.$emit("wujw_common_dialog", type); // #ifdef APP const store = getApp().globalData.store store.commit('setAppDialogShow', false) // #endif } } } </script> <style lang="scss"> $btncolor: #ff6a00; page { background: transparent; } .mask-content { position: fixed; left: 0; top: 0; right: 0; bottom: 0; display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.4); .dialog-content { background-color: #FFFFFF; width: 580rpx; border-radius: 10rpx; .head-content { display: flex; align-items: center; justify-content: center; color: #343434; font-weight: bold; font-size: 32rpx; padding: 20rpx 30rpx; } .main-content { max-height: 330rpx; .info-content { min-height: 80rpx; padding: 10rpx 30rpx; color: #636463; font-size: 30rpx; display: flex; justify-content: center; align-items: center; } } .foot-content { display: flex; justify-content: center; align-items: center; height: 110rpx; .btn { font-size: 28rpx; border-radius: 66rpx; height: 66rpx; display: flex; justify-content: center; align-items: center; &:active{ background-color: #eeeeee; } } &.alert { .btn { background-color: $btncolor; color: #FFFFFF; font-size: 28rpx; border-radius: 60rpx; height: 66rpx; width: 300rpx; padding: 0 40rpx; display: flex; justify-content: center; align-items: center; } } &.confirm { justify-content: space-around; .btn { min-width: 230rpx; &.active { background-color: $btncolor; color: #FFFFFF; } &.cancel { border: 1rpx solid $btncolor; color: $btncolor; border-radius: 66rpx; } } } } } } </style>

dialogUtil.js

import dialog from "@/components/dialog/dialog.js" export default { /** * 弹出提示 */ alert({ title = "", content = "", confirmText = '确定', callback, }) { // #ifdef APP-PLUS dialog.alert({ content, title, confirmText }, callback) // #endif // #ifndef APP-PLUS uni.showModal({ title, content, confirmText, showCancel: false, confirmColor: '#ff6a00', success: callback }) // #endif }, /** * 确认提示框 */ confirm({ title = "提示", content = "", confirmText = '确定', cancelText = '取消', confirm, cancel }) { // #ifdef APP-PLUS dialog.confirm({ content, title, confirmText, cancelText, }, confirm, cancel) // #endif // #ifndef APP-PLUS uni.showModal({ title, content, cancelText, confirmText, confirmColor: '#ff6a00', success: (e) => { if (e.confirm) { confirm && confirm() } else if (e.cancel) { cancel && cancel() } }, fail: (e) => { console.log(e) } }) // #endif }, }

(2)配置page.json

在pages的最底部设置(APP端才需要)

// #ifdef APP-PLUS , { "path": "components/dialog/dialog", "style": { "navigationStyle": "custom", // #ifdef APP-PLUS "backgroundColor": "transparent", "backgroundColorTop": "transparent", "backgroundColorBottom": "transparent", // #endif "app-plus": { "animationType": "fade-in", "background": "transparent", "popGesture": "none" } } } // #endif

(3)配置App.vue

<script> import dialog from "@/components/dialog/dialogUtil.js" export default { async onLaunch() { uni['dialog'] = dialog; }, } </script>

(4)调用

注意:不需要再次引入组件,可直接在script调用

// 显示双按钮 uni.dialog.confirm({ title: "温馨提示", content: "您当前的网络不稳定,请检查网络状态", confirmText: "好的", confirm: () => { console.log("已点击确认"); }, }); // 显示单按钮 uni.dialog.alert({ content: "您当前的网络不稳定,请检查网络状态", confirm: () => { console.log("已点击确认"); }, });

(5)注意App端的一个问题

在uniapp(App端)中实现自定义弹框,可以通过创建一个透明页面来实现。点击进入当前页面时,页面背景会变透明,用户可以根据自己的需求进行自定义,最终效果类似于弹框。

遇到问题:当打开弹窗(进入弹窗页面)就会触发当前页面的onHide函数,关闭弹窗(跳出弹窗页面)就会触发上一页的onShow函数。有时候我们在onShow、onHide函数会定义自己的逻辑处理,比如在onShow函数发请求、在onHide销毁定时器,那么当打开关闭弹窗都会触发一遍。当打开关闭弹窗避免不触发自己定义的逻辑处理,这问题怎么解决呢?

解决逻辑:

1、我们可以在vuex定义一个变量,默认为false,当打开弹窗(进入弹窗页面)之前把该变量改成true,关闭弹窗(跳出弹窗页面)之后把该变量改成false。(或者直接使用uni.getStorageSync本地存储和uni.removeStorageSync删除缓存也可以。)

2、在调用弹窗的页面的onShow、onHide函数获取到该变量,判断变量如果为true,直接结束函数。
vuex的store 定义一个弹窗状态和改变状态的方法

state: { appDialogShow: false, }, mutations: { setAppDialogShow(state, show) { state.appDialogShow = show; },

App进入、进出弹窗页面改变弹窗状态


App端在页面调用弹窗组件,就会触发onShow、onHide函数,需要做判断禁止再次触发

H5效果图

微信小程序效果图

App效果图

http://www.jsqmd.com/news/200883/

相关文章:

  • 重组蛋白AVI标签技术详解:生物素化策略与亲和纯化应用
  • CPU三大核心部件功能详解
  • 鸿蒙电脑亮相 中国国产操作系统再次突破
  • 百度免费大模型API深度解析 大厂llm大模型市场国产大模型API免费全平台对比指南,薅羊毛指南与实战建议 政策深度解析与 - 教程
  • 【图像加密】Lorenz超混沌系统和Rivest-Shamir-Adleman(RSA)算法的新图像加密方案附matlab代码
  • 关于dify 工作流的LLM并发顺序执行问题的复盘
  • 【转载】权限控制模型
  • 专业音乐喷泉厂家怎么选?这3家别错过!
  • Docker + containerd 存储和启动完整原理
  • 导师推荐!自考必备AI论文软件TOP8:8款深度测评与推荐
  • 行业观察:2026生成式引擎优化(GEO)的范式转移与服务商能力重构 摘要 - 速递信息
  • 联机分析处理(OLAP)通过数据立方体模型支持多维数据分析
  • 【图像加密】基于超混沌系统和斐波那契 Q 矩阵的新图像加密算法研究附matlab代码
  • Modbus TCP Java入门 - 指南
  • JavaScript DOM 核心操作:从内容到节点的实战指南
  • TF卡系列、SD卡系列、CF卡系列有什么区别呢?我本来应该买TF卡系列,用在树莓派上面的。
  • Oracle RAS:AI时代企业数据安全核心
  • 【拯救HMI】工业HMI常见故障及排查方法:黑屏、通信中断、操作无响应,新手别慌
  • 安全体验馆!优质供应商榜单:口碑评估维度与采购参考指南
  • 快快网络入选福州市网络与信息安全信息通报中心2026年度网络安全技术支撑单位
  • 2026必备!10个AI论文工具,继续教育学生轻松搞定毕业论文!
  • 揭秘GEO:AI时代,如何让你的品牌被ChatGPT“点名”推荐?
  • 杰和IM1-210核心板用模块化设计重新定义工业主板开发
  • 数眼智能搜索API VS 腾讯(搜狗)搜索API:技术赋能下的差异化价值绽放
  • 彼得林奇的“买入并持有“策略
  • 享元模式
  • 如何保证rabbitmq或kafka 消息不丢失,从生产到消费端全过程
  • 数眼智能搜索 API VS 安思派搜索 API,谁是 AI 应用的最佳信息搭档?
  • TX Text Control ActiveX 34.0 FIX
  • LangGraph人机协同(HITL)实战:三种核心模式详解+企业部署避坑指南