前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >加强版uniapp全端弹出框组件|uni-app自定义扩展popup

加强版uniapp全端弹出框组件|uni-app自定义扩展popup

原创
作者头像
andy2018
修改2021-07-12 11:02:50
11.4K0
修改2021-07-12 11:02:50
举报
文章被收录于专栏:h5

写在前面

目前在uniapp项目开发中,使用比较多的弹框是官方扩展的uni-popup组件和uView-ui提供的u-popup组件。使用过的都知道,功能有一些局限性。

今天主要给大家分享最新研发的uniapp增强版弹窗组件UAPopup

如上图:编译到H5/小程序/App端效果。

支持多种弹窗类型及动画效果。组件式+函数式调用方式。可在Nvue页面完美运行显示。

引入组件

在main.js中全局引入组件。

代码语言:javascript
复制
import uaPopup from './components/ua-popup/index.vue'
Vue.component('ua-popup', uaPopup)

hbuilderx2.5 支持easycom引入模式。根据需要也可以改为此种方式,无需手动注册引入。

调用组件

  • 组件式
代码语言:javascript
复制
<!-- msg提示(自定义背景) -->
<ua-popup
    v-model="showMsgBg"
    anim="footer"
    content="hello uniapp"
    shade="false"
    time="2"
    :custom-style="{'backgroundColor': 'rgba(0,0,0,.6)', 'color': '#fff'}"
/>

<!-- 询问框 -->
<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},
    ]"
/>
  • 函数式
代码语言:javascript
复制
// 函数式嵌套调用
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'},
				zIndex: 202120,
				btns: [
					{
						text: 'close', click() {
							$ua.close()
						}
					},
					{
						text: 'Get一下',
						style: 'color:#00aa00;',
						click() {
							$toast.open({
								type: 'toast',
								icon: 'loading',
								content: '请稍后...',
								opacity: .2,
								time: 2,
								zIndex: 202125,
							})
						}
					}
				]
			})
		}
	})
},
handleBtnClick() {
	this.$refs.uapopup.open({
		content: '正在操作中,请稍后...',
		shadeClose: false,
		anim: 'footer',
		customStyle: {'background-color': 'rgba(0, 170, 0, 0.6)', 'color': '#fff', 'border-radius': '6px'},
		opacity: .1,
		time: 2,
		onClose: () => {
			this.$refs.uatoast.open({
				type: 'toast', icon: 'success', content: '操作成功', time: 2,
			})
		}
	});
},

说明:对于一些复杂的弹窗场景,可以使用组件式,自定义内容插槽实现。一些简单的提示,则使用函数式即可。

代码语言:javascript
复制
<!-- msg提示 -->
<ua-popup v-model="showMsg" anim="fadeIn" content="上善若水,水利万物而不争" shadeClose="false" time="3" />

<!-- 自定义多按钮 -->
<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},
	]"
/>
代码语言:javascript
复制
<!-- 底部对话框 -->
<ua-popup v-model="showFooter" anim="footer" type="footer" :shadeClose="false"
	content="真正觉悟的一刻,是放下追寻外在世界的财富,而开始追寻内心世界的真正财富。"
	:btns="[
		{text: 'Get到了', style: 'color:#00e0a1;', click: handleInfo},
		{text: '收藏', style: 'color:#ee0a24;'},
		{text: '取消', style: 'color:#a9a9a9;', click: hideFooter},
	]"
/>

<!-- ActionSheet底部弹出式菜单(仿微信weui-picker顶部按钮) -->
<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>
代码语言:javascript
复制
<ua-popup v-model="showToast" type="toast" icon="loading" time="2" content="加载中..." />
<ua-popup v-model="showToast" type="toast" icon="success" shade="false" time="2" content="成功提示" />
<ua-popup v-model="showToast" type="toast" icon="fail" shade="false" time="2" content="失败提示" />
<ua-popup v-model="showToast" type="toast" icon="warn" shade="false" time="2" content="提示" />
<ua-popup v-model="showToast" type="toast" icon="info" shade="false" time="2" content="普通提示" />

另外还支持类似微信长按弹窗效果。

代码语言:javascript
复制
<ua-popup v-model="showContextMenu2" type="contextmenu" :follow="follow2" opacity="0"
	:btns="[
		{text: '置顶联系人', click: handleContextPopup},
		{text: '设置备注信息'},
		{text: '星标好友'},
		{text: '删除', click: hideContextMenu1},
	]"
>
</ua-popup>

参数配置

支持超过20+参数配置。

代码语言:javascript
复制
## 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     	关闭弹窗回调

弹窗组件模板

代码语言:javascript
复制
<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>

ok,基于uni-app跨端自定义弹窗组件就分享到这里。感谢大家的阅读~~

https://cloud.tencent.com/developer/article/1825924

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 引入组件
  • 调用组件
  • 参数配置
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档