x***@126.com
x***@126.com
  • 发布:2021-07-11 07:26
  • 更新:2024-03-27 09:18
  • 阅读:5206

『兼容H5+小程序+App/Nvue』uniapp自定义弹框uaPopup组件(升级版)

分类:uni-app

基于uni-app开发兼容全端自定义弹出框ua-popup插件,可完美运行在h5、小程序及app端。

uaPopup 一款整合了msg信息框、alert提示框、dialog对话框、actionSheet底部面板框、toast轻提示框、android/ios弹窗等多种弹窗效果。可以自定义弹窗样式及按钮样式和事件、多个弹窗嵌套显示,支持自定义插槽模板内容。

如下图:h5/小程序/app端效果
img

可覆盖在Nvue原生页面video组件之上

img

引入组件

uapopup 支持全局main.js引入或页面单独引入使用。

import UAPopup from './components/ua-popup/index.vue'  
Vue.component('ua-popup', UAPopup)

自hbuilderx2.5起 支持easycom组件模式。根据使用习惯,也可以改为components/ua-popup/ua-popup.vue方式,系统会自定义识别组件,无需再手动注册引入。

使用组件

ua-popup支持组件写法和函数式写法来调用组件。

  • 组件式调用
<!-- msg提示 -->  
<ua-popup v-model="showMsg" anim="fadeIn" content="上善若水,水利万物而不争" shadeClose="false" time="3" />  

<!-- 询问框 -->  
<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},  
    ]"  
/>
  • 函数式调用
// 函数式多层嵌套  
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,  
                            })  
                        }  
                    }  
                ]  
            })  
        }  
    })  
}

img

img

编码开发

  • 支持如下20+参数自定义配置。
props: {  
    value: { type: Boolean, default: false },  
    title: String,  
    content: String,  
    type: String,  
    customStyle: { type: Object, default: null },  
    icon: String,  
    shade: { type: [Boolean, String], default: true },  
    shadeClose: { type: [Boolean, String], default: true },  
    opacity: { type: [Number, String], default: '' },  
    round: Boolean,  
    xclose: Boolean,  
    xposition: { type: String, default: 'right' },  
    xcolor: { type: String, default: '#333' },  
    anim: { type: String, default: 'scaleIn' },  
    position: String,  
    follow: { type: Array, default: null },  
    time: { type: [Number, String], default: 0 },  
    zIndex: { type: [Number, String], default: '202107' },  
    btns: {  
        type: Array, default: null  
    },  
    // 打开弹框回调  
    onOpen: { type: Function, default: null },  
    // 关闭弹框回调  
    onClose: { type: Function, default: null },  
}
  • 弹窗模板template
<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="''+uuid" :class="[''+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'+opts.icon]" :style="{'background-image': `url(${toastIcon[opts.icon]})`}"></view> -->  
                <image v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast'+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>
  • 核心逻辑处理
<script>  
    /**  
     * @Desc     uniapp跨端自定义popup组件  
     * @Time     andy by 2021/7/10  
     * @About    Q:282310962  wx:xy190310  
     */  

    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('#' + 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>

基本可通过组件式+函数式组合开发出一些复杂的弹窗应用场景。

okey,基于uniapp开发自定义弹窗组件就分享到这里了。希望对大家有些帮助哈~~✍✍

链接:https://juejin.cn/post/6977298346905960456/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 关注 分享

要回复文章请先登录注册

x***@126.com

x***@126.com (作者)

[https://gf.bilibili.com/item/detail/1105131011](https://gf.bilibili.com/item/detail/1105131011)
2024-03-27 09:18
baobiao

baobiao

uaPopup 插件地址呢?
2022-02-24 10:42
这是谁的部将

这是谁的部将

uaPopup 插件地址呢?
2021-08-18 17:09
1***@qq.com

1***@qq.com

怎么安装ua-popup插件
2021-08-03 15:45
x***@126.com

x***@126.com (作者)

1、uniapp多端自定义顶部导航栏组件
![](https://img-cdn-aliyun.dcloud.net.cn/stream/plugin_screens/60e958c0-e1ea-11eb-8daa-cdb1d3a128b3_2.png)
[https://ext.dcloud.net.cn/plugin?id=5592](https://ext.dcloud.net.cn/plugin?id=5592)

2、uniapp全端自定义底部tabbar组件
![](https://img-cdn-aliyun.dcloud.net.cn/stream/plugin_screens/82bd9e40-e1fa-11eb-a2bb-3783fb0c586e_2.png)
[https://ext.dcloud.net.cn/plugin?id=5593](https://ext.dcloud.net.cn/plugin?id=5593)
2021-07-19 07:45