最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue3.0自定义插件|vue3弹框组件V3Popup

    正文概述 掘金(xiaoyan2015)   2021-01-01   519

    概述

    vue3.0自定义插件|vue3弹框组件V3Popup

    如上图:在功能效果及UI上基本保持和之前vue2.x的完美一致。

    引入组件

    在main.js中全局引入使用。

    import { createApp } from 'vue'
    import App from './App.vue'
    
    // 引入弹窗组件v3popup
    import V3Popup from './components/v3popup'
     
    createApp(App).use(V3Popup).mount('#app')
    

    同样的支持组件式函数式两种灵活调用方式。

    组件式

    <!-- 提示框 -->
    <v3-popup v-model="showMsg" anim="fadeIn" content="msg提示框测试(3s后窗口关闭)" shadeClose="false" time="3" />
     
    <!-- 询问框 -->
    <v3-popup v-model="showConfirm" shadeClose="false"  xclose z-index="2020"
        content="<div style='color:#1be769;padding:20px;'>确认框(这里是确认框提示信息,这里确认框提示信息,这里是确认框提示信息)</div>"
        :btns="[
            {text: '取消', click: () => showConfirm=false},
            {text: '确定', style: 'color:#f90;', click: handleInfo},
        ]"
    />
    

    函数式

    let $el = this.$v3popup({
        title: '标题',
        content: '<div style='color:#f90;padding:10px;'>这里是内容信息!</div>',
        type: 'android',
        shadeClose: false,
        xclose: true,
        btns: [
            {text: '取消', click: () => { $el.close(); }},
            {text: '确认', style: 'color:#f90;', click: () => handleOK},
        ],
        onSuccess: () => {},
        onEnd: () => {}
    })
    

    大家都知道在vue2.x中可以通过prototype原型链挂载全局方法,那么在vue3中如何挂载全局方法呢?

    其实vue3提供了两种可供全局调用的方法。app.config.globalPropertiesapp.provide

    如果是通过app.config.globalProperties.$v3popup = V3Popup 这种方式挂载。

    // vue2.x中调用
    methods: {
        showDialog() {
            this.$v3popup({...})
        }
    }
     
    // vue3.x中调用
    setup() {
        // 获取上下文
        const { ctx } = getCurrentInstance()
        ctx.$v3popup({...})
    }
    

    如果是通过app.provide('v3popup', V3Popup) 这种方式。

    // vue2.x中调用
    methods: {
        showDialog() {
            this.v3popup({...})
        }
    }
     
    // vue3.x中调用
    setup() {
        const v3popup = inject('v3popup')
        
        const showDialog = () => {
            v3popup({...})
        }
     
        return {
            v3popup,
            showDialog
        }
    }
    

    不过尤大大更是推荐使用 provide inject 这种方式。大家可以根据项目情况,自行选择合适的方式即可。

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue3.0自定义插件|vue3弹框组件V3Popup

    参数配置

    v3popup提供了**20+**种参数任意搭配组合。

    |props参数|
    v-model         是否显示弹框
    title           标题
    content         内容(支持String、带标签内容、自定义插槽内容)***如果content内容比较复杂,推荐使用标签式写法
    type            弹窗类型(toast | footer | actionsheet | actionsheetPicker | android | ios)
    popupStyle      自定义弹窗样式
    icon            toast图标(loading | success | fail)
    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          弹窗层叠(默认8080)
    teleport        指定挂载节点(默认是挂载组件标签位置,可通过teleport自定义挂载位置) teleport="body | #xxx | .xxx"
    btns            弹窗按钮(参数:text|style|disabled|click)
    ++++++++++++++++++++++++++++++++++++++++++++++
    |emit事件触发|
    success         层弹出后回调(@success="xxx")
    end             层销毁后回调(@end="xxx")
    ++++++++++++++++++++++++++++++++++++++++++++++
    |event事件|
    onSuccess       层打开回调事件
    onEnd           层关闭回调事件
    

    以上自定义参数足以应对各种弹窗应用场景。

    <template>
        <div ref="elRef" v-show="opened" class="vui__popup" :class="{'vui__popup-closed': closeCls}" :id="id">
            <!-- //蒙层 -->
            <div v-if="JSON.parse(shade)" class="vui__overlay" @click="shadeClicked" :style="{opacity}"></div>
            <div class="vui__wrap">
                <div class="vui__wrap-section">
                    <div class="vui__wrap-child" :class="['anim-'+anim, type&&'popupui__'+type, round&&'round', position]" :style="[popupStyle]">
                        <div v-if="title" class="vui__wrap-tit" v-html="title"></div>
                        <div v-if="type=='toast'&&icon" class="vui__toast-icon" :class="['vui__toast-'+icon]" v-html="toastIcon[icon]"></div>
                        <!-- 判断插槽是否存在 -->
                        <template v-if="$slots.content">
                            <div class="vui__wrap-cnt"><slot name="content" /></div>
                        </template>
                        <template v-else>
                            <div v-if="content" class="vui__wrap-cnt" v-html="content"></div>
                        </template>
                        <slot />
                        <div v-if="btns" class="vui__wrap-btns">
                            <span v-for="(btn, index) in btns" :key="index" class="btn" :style="btn.style" @click="btnClicked($event, index)" v-html="btn.text"></span>
                        </div>
                        <span v-if="xclose" class="vui__xclose" :class="xposition" :style="{'color': xcolor}" @click="close"></span>
                    </div>
                </div>
            </div>
        </div>
    </template>
     
    /**
     * @Desc     Vue3.0自定义弹层V3Popup
     * @Time     andy by 2020-12
     * @About    Q:282310962  wx:xy190310
     */
    <script>
        import { onMounted, ref, reactive, watch, toRefs, nextTick } from 'vue'
        let $index = 0, $locknum = 0, $timer = {}
        export default {
            props: {
                // 接收父组件v-model值,如果v-model:open,则这里需写open: {...}
                modelValue: { type: Boolean, default: false },
                // 标识符,相同ID共享一个实例
                id: {
                    type: String, default: ''
                },
                title: String,
                content: String,
                type: String,
                popupStyle: String,
                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: '8080' },
                teleport: [String, Object],
                btns: {
                    type: Array, default: null
                },
                onSuccess: { type: Function, default: null },
                onEnd: { type: Function, default: null },
            },
            emits: [
                'update:modelValue'
            ],
            setup(props, context) {
                const elRef = ref(null)
     
                const data = reactive({
                    opened: false,
                    closeCls: '',
                    toastIcon: {
                        ...
                    }
                })
     
                onMounted(() => {
                    ...
                })
     
                // 监听弹层v-model
                watch(() => props.modelValue, (val) => {
                    if(val) {
                        open()
                    }else {
                        close()
                    }
                })
     
                // 打开弹层
                const open = () => {
                    if(data.opened) return
                    data.opened = true
                    typeof props.onSuccess === 'function' && props.onSuccess()
     
                    const dom = elRef.value
                    dom.style.zIndex = getZIndex() + 1
     
                    ...
     
                    // 倒计时
                    if(props.time) {
                        $index++
                        // 避免重复操作
                        if($timer[$index] !== null) clearTimeout($timer[$index])
                        $timer[$index] = setTimeout(() => {
                            close()
                        }, parseInt(props.time) * 1000)
                    }
     
                    // 长按|右键菜单
                    if(props.follow) {
                        ...
                    }
                }
     
                // 关闭弹层
                const close = () => {
                    if(!data.opened) return
     
                    data.closeCls = true
                    setTimeout(() => {
                        ...
     
                        context.emit('update:modelValue', false)
                        typeof props.onEnd === 'function' && props.onEnd()
                    }, 200)
                }
     
                // 点击遮罩层
                const shadeClicked = () => {
                    if(JSON.parse(props.shadeClose)) {
                        close()
                    }
                }
                // 按钮事件
                const btnClicked = (e, index) => {
                    let btn = props.btns[index];
                    if(!btn.disabled) {
                        typeof btn.click === 'function' && btn.click(e)
                    }
                }
                
                ...
     
                return {
                    ...toRefs(data),
                    elRef,
                    close,
                    shadeClicked,
                    btnClicked,
                }
            }
        }
    </script>
    

    以上就是vue3实现弹窗的模板及核心逻辑处理部分。

    vue3.0自定义插件|vue3弹框组件V3Popup

    vue2.x中可以通过Vue.extend扩展实例方法来实现函数调用。

    // vue2.x实现函数调用
    import Vue from 'vue';
    import VuePopup from './popup.vue';
    
    let PopupConstructor = Vue.extend(VuePopup);
    
    let $instance;
    $instance = new PopupConstructor({
    	propsData: options
    });
    
    ...
    

    那么在vue3.0中则是需要通过createAppcreateVNode render来实现

    import { createApp } from 'vue'
    import PopupConstructor from './popup.vue'
     
    let $inst
    // 创建挂载实例
    let createMount = (opts) => {
        const mountNode = document.createElement('div')
        document.body.appendChild(mountNode)
     
        const app = createApp(PopupConstructor, {
            ...opts, modelValue: true,
            remove() {
                app.unmount(mountNode)
                document.body.removeChild(mountNode)
            }
        })
        return app.mount(mountNode)
    }
     
    function V3Popup(options = {}) {
        options.id = options.id || 'v3popup_' + generateId()
        $inst = createMount(options)
        
        return $inst
    }
     
    V3Popup.install = app => {
        app.component('v3-popup', PopupConstructor)
        // app.config.globalProperties.$v3popup = V3Popup
        app.provide('v3popup', V3Popup)
    }
    

    vue3.0自定义插件|vue3弹框组件V3Popup

    好了,基于vue3.0开发自定义弹出框组件就介绍到这里。最近正在筹备vue3实例项目,届时也会分享出来。希望以上分享对大家有些帮助!

    Flutter+Dart仿微信App聊天实例

    ❤️ 结语

    如果你觉得这篇内容对你有启发或帮助,那么可以帮我三个小忙:

    1. 转发/点赞,让更多的人也能看到这篇分享。
    2. 加关注、不迷路,不定期分享原创技术知识。
    3. 也看看其它历史文章。

    起源地下载网 » vue3.0自定义插件|vue3弹框组件V3Popup

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元