ua-popup 基于uniapp增强版弹框|对话框|模态框组件。支持超过20+参数、6+弹窗类型及多种弹窗动画,可编译到h5+app+小程序端,可使用组件式+函数式两种调用方式。
由于uniapp内置的弹窗并不能满足一些复杂的应用场景。只能使用自定义组件来实现效果。虽然官方提供的uni-popup或uview提供的popup组件也能实现一些弹窗效果。但是调用方式非常单一。并不能实现多样化需求。
// 引入自定义弹框组件 import uaPopup from './components/ua-popup/index.vue' Vue.component('ua-popup', uaPopup)
当然也可以改为easycom模式来引入。components/ua-popup/ua-popup.vue
ua-popup可以支持标签方式+函数式调用。
<ua-popup v-model="showConfirm" shadeClose="false" title="标题" xclose z-index="2001" content="<div style='color:#ff557f;padding:20px 40px;'>一切都将一去杳然,任何人都无法将其捕获。</div>" :btns="[ {text: '取消', click: hideConfirm}, {text: '确定', style: 'color:#00aa00;', click: handleInfo}, ]" />
<script> export default { methods: { // 函数式嵌套调用 handleInfo() { let $ua = this.$refs.uapopup let $toast = this.$refs.uatoast $ua.open({ content: '人生漫漫,且行且珍惜', customStyle: {'background-color': 'rgba(170, 0, 127, 0.6)', 'color': '#fff'}, time: 3, onClose() { $ua.open({ type: 'android', content: '<div style="color:#aa007f">预测未来的最好办法是自己亲手创造未来</div>', customStyle: {'width': '200px'}, btns: [ { text: 'close', click() { $ua.close() } }, { text: 'Get一下', style: 'color:#00aa00;', click() { $toast.open({ type: 'toast', icon: 'loading', content: '请稍后...', opacity: .2, time: 2, }) } } ] }) } }) }, } } </script>
对于一些简单提示效果,使用函数式比较方便。一些复杂点的模板可以使用组件式slot插槽
调用。
标题和内容支持富文本插入,并且内容还支持插槽自定义模板内容。
<ua-popup v-model="showMulityBtns" anim="fadeInDown" title="<b style='color:#03a9f4;'>Title</b>" :z-index="6666" content="<div style='padding:10px 35px;'>Lately did you ever feel the pain In the morning as it soaks it to the bone?</div>" :btns="[ {text: 'later', style: 'color:#aa557f;'}, {text: 'cancel', style: 'color:#ff5500;'}, {text: 'ok', style: 'color:#00aa00;', click: handleInfo}, ]" />
<ua-popup v-model="showActionPicker" anim="footer" type="actionsheetPicker" round title="标题" :btns="[ {text: '取消'}, {text: '确定', style: 'color:#00aa00;', click: handleInfo}, ]" > <!-- 自定义内容 --> <ul class="list" style="padding:50px;"> <li>只要不失去方向,就不会失去自我</li> <li>别问别人为什么,多问自己凭什么</li> <li>不要等待机会,而要创造机会</li> </ul> </ua-popup>
<ua-popup v-model="showComponent" xclose xposition="top" :shadeClose="false" content="自定义模板信息" :btns="[ {text: '确认', style: 'color:#00aa00;', click: hideComponent}, ]" @open="handleOpen" @close="handleClose" > <template slot="content"><div style="color:#aa007f;padding: 0 10px;">实力的来源不是胜利。唯有奋斗才能增强实力。当你历经苦难而不气馁,那便是实力。</div></template> <view style="padding: 0 20px 20px;"> <image src="https://img.yzcdn.cn/vant/apple-2.jpg" style="width:100%;" @click="handleContextPopup" /> </view> </ua-popup>
## props [参数配置] v-model 当前组件是否显示 title 标题(支持富文本div标签、自定义插槽内容) content 内容(支持富文本div标签、自定义插槽内容) type 弹窗类型(toast | footer | actionsheet | actionsheetPicker | android/ios) customStyle 自定义弹窗样式 icon toast图标(loading | success | fail | warn | info) shade 是否显示遮罩层 shadeClose 是否点击遮罩时关闭弹窗 opacity 遮罩层透明度 round 是否显示圆角 xclose 是否显示关闭图标 xposition 关闭图标位置(left | right | top | bottom) xcolor 关闭图标颜色 anim 弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown) position 弹出位置(top | right | bottom | left) follow 长按/右键弹窗(坐标点) time 弹窗自动关闭秒数(1、2、3) zIndex 弹窗层叠(默认202107) btns 弹窗按钮(参数:text|style|disabled|click) ------------------------------------------ ## slot [插槽] <template slot="title"></template> <template slot="content"></template> ------------------------------------------ ## emit open 打开弹出层时触发(@open="xxx") close 关闭弹出层时触发(@close="xxx") ------------------------------------------ ## event onOpen 打开弹窗回调 onClose 关闭弹窗回调
<template> <!-- #ifdef APP-NVUE --> <view v-if="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}"> <!-- #endif --> <!-- #ifndef APP-NVUE --> <view v-show="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}"> <!-- #endif --> <!-- 遮罩层 --> <view v-if="opts.shade && opts.shade!='false'" class="uapopup__overlay" @touchstart="handleShadeClick" :style="{'opacity': opts.opacity >= 0 ? opts.opacity : '', 'z-index': oIndex-1}"></view> <!-- 窗口层 --> <view class="uapopup__wrap" :style="{'z-index': oIndex}"> <view class="uapopup__child" :id="'uapopup-'+uuid" :class="['anim-'+opts.anim, opts.type&&'popui__'+opts.type, opts.round&&'round', opts.position]" :style="[opts.follow&&positionStyle, opts.customStyle]"> <!-- //标题 --> <view v-if="opts.title || $slots.title" class="uapopup__title"> <template v-if="$slots.title"><slot name="title" /></template> <rich-text v-else :nodes="opts.title"></rich-text> </view> <!-- //toast --> <!-- <view v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast__icons-'+opts.icon]" :style="{'background-image': `url(${toastIcon[opts.icon]})`}"></view> --> <image v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast__icons-'+opts.icon]" :src="toastIcon[opts.icon]" mode="widthFix"></image> <!-- //内容 --> <view v-if="opts.content || $slots.content" class="uapopup__content"> <template v-if="$slots.content"><slot name="content" /></template> <rich-text v-else :nodes="opts.content"></rich-text> </view> <slot /> <!-- //按钮组 --> <view v-if="opts.btns" class="uapopup__actions"> <rich-text v-for="(btn,index) in opts.btns" :key="index" class="btn" :class="{'disabled': btn.disabled}" :style="btn.style" @click="handleBtnClick($event, index)" :nodes="btn.text"></rich-text> </view> <!-- //关闭按钮 --> <view v-if="opts.xclose" class="uapopup__xclose" :class="opts.xposition" :style="{'color': opts.xcolor}" @click="close"></view> </view> </view> </view> </template> /** * @Desc uniapp全端自定义弹框组件 * @Time andy by 2021/7/10 * @About Q:282310962 wx:xy190310 */ <script> let index = 0 export default { ... data() { return { // 混入props参数,处理函数式调用 opts: { visible: false, }, toastIcon: { ... }, closeAnim: false, oIndex: 202107, timer: null, // 长按定位初始化(避免弹框跳动闪烁) positionStyle: { position: 'absolute', left: '-999px', top: '-999px' }, } }, watch: { value(val) { const type = val ? 'open' : 'close' this[type]() } }, computed: { uuid() { return Math.floor(Math.random() * 10000) }, }, methods: { // 打开弹框 open(options) { if(this.opts.visible) return this.opts = Object.assign({}, this.$props, options) this.opts.visible = true // nvue 的各组件在安卓端默认是透明的,如果不设置background-color,可能会导致出现重影的问题 // #ifdef APP-NVUE if(!this.opts.customStyle['background'] && !this.opts.customStyle['background-color']) { this.opts.customStyle['background'] = '#fff' } // #endif let _index = ++index this.oIndex = _index + parseInt(this.opts.zIndex) this.$emit('open') typeof this.opts.onOpen === 'function' && this.opts.onOpen() // 长按处理 if(this.opts.follow) { ... } ... }, // 关闭弹框 close() { if(!this.opts.visible) return this.closeAnim = true setTimeout(() => { this.opts.visible = false this.closeAnim = false this.$emit('input', false) this.$emit('close') typeof this.opts.onClose === 'function' && this.opts.onClose() this.timer && clearTimeout(this.timer) delete this.timer }, 200) }, ... // 获取dom宽高 getDom(id) { return new Promise((resolve, inject) => { uni.createSelectorQuery().in(this).select('#uapopup-' + id).fields({ size: true, }, data => { resolve(data) }).exec() }) }, // 自适应坐标点 getPos(x, y, ow, oh, winW, winH) { let l = (x + ow) > winW ? x - ow : x; let t = (y + oh) > winH ? y - oh : y; return [l, t]; }, } } </script>
在nvue原生页面运行效果,兼容性不错。
另外还支持类似微信长按弹窗效果。
<!-- 长按弹窗1 --> <ua-popup v-model="showContextMenu1" type="contextmenu" :follow="follow1" opacity=".35" :btns="[ {text: '置顶聊天', click: handleContextPopup}, {text: '标记为未读', style: 'color:#00aa00;'}, {text: '少一点预设的期盼,那份对人的关怀会更自在', style: 'color:#ff007f;'}, {text: '心有多大,舞台就有多大', style: 'color:#09f;'}, {text: '关闭', style: 'color:#aaaa7f;', click: hideContextMenu1}, ]" > </ua-popup> <!-- 长按弹窗2 --> <ua-popup v-model="showContextMenu2" type="contextmenu" :follow="follow2" opacity="0" :btns="[ {text: '置顶联系人', click: handleContextPopup}, {text: '设置备注信息'}, {text: '星标好友'}, {text: '删除', click: hideContextMenu1}, ]" > </ua-popup>
end, 使用uni-app自定义多端弹窗插件就介绍到这里。希望能喜欢~~
https://blog.csdn.net/yanxinyun1990/article/details/118187205
https://blog.csdn.net/yanxinyun1990/article/details/114162969