组件介绍

UA-Popup 一款基于 uniapp 开发的轻量级多端自定义弹框组件。反对超过20+参数配置、组件式+函数式两种调用形式。完满运行到h5+App端+小程序Nvue原生组件页面。

如上图:兼容h5+小程序+App端,运行成果统一。

导入组件

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

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

当然,也反对 easycom 模式。能够省略下面这一步导入。

反对组件式写法函数调用两种形式。

  • 组件式调用
<!-- 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,            })        }    });},

  • 底部面板弹框

<!-- 底部对话框 --><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底部弹出式菜单 --><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>
  • Toast轻提示框

<ua-popup v-model="showToast" type="toast" icon="loading" time="2" content="加载中..." />
  • 仿微信长按弹框成果

<!-- 长按弹窗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>

开发实现

  • 自定义参数配置
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>    <!-- #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页面运行成果。仍然能够笼罩在video原生组件之上。

大家能够依据我的项目须要,本人定制一些扩大性能。实现多样化弹框场景。

ok,应用uniapp自定义弹框组件就介绍到这里。心愿各位喜爱哈~~✍

uniapp自定义导航条+底部tabbar组件