[HBuilderX]uni-app全端自定义模态框组件uaPopup(升级版)

uni-app全端自定义模态框组件uaPopup(升级版)

uaPopup 基于uniapp开发的兼容多端h5+小程序+app端自定义弹框组件。

快速引入

在main.js中全局引入。

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

也可以使用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="showInfo" anim="scaleIn"
    content="阳光下人走不出自己的影子,黑暗中人看不见自己的影子。只要还有明天,今天就永远是起跑线。"
    :btns="[
        {text: '知道了', style: 'color:#999;', click: hideInfo},
    ]"
/>
  • 函数式
// 函数式嵌套调用
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,
            })
        }
    });
},

实现过程

  • 支持20+参数配置
    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               弹窗自动关闭秒数(123)
    zIndex             弹窗层叠(默认202107)
    btns               弹窗按钮(参数:text|style|disabled|click)
    open                打开弹出层时触发(@open="xxx")
    close               关闭弹出层时触发(@close="xxx")
    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>

<script>
/**
 * @Desc     uniapp全端自定义弹框组件
 * @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('#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>

好了,以上就是uniapp开发自定义弹窗的分享。希望对大家有些帮助!

1.本站默认解压密码为:xiaoqingtai.com
2.本站所有内容均由互联网收集整理,仅供大家参考、学习,禁止商用。
3.本站所有内容版权归原著所有,如有侵权请及时联系我们做删除处理。
请扫描下方二维码关注微信公众号或直接微信搜索“小青苔基地”关注
小青苔基地 » [HBuilderX]uni-app全端自定义模态框组件uaPopup(升级版)

发表评论