Vue3-Popup 基于vue3构建的手机端自定义弹层组件。
一款集合了msg、alert、dialog、modal、actionSheet、toast等多种效果的Vue3自定义弹层组件。支持上下左右弹出、圆角、自定义弹层样式、多按钮及长按/右键功能。
引入v3popup
// 在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\" title=\"标题\" 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: () => {} })
vue3中可通过 和
两种方式挂载类似vue2中prototype原型链方法。
通过 方式挂载。
// vue2中调用 methods: { showDialog() { this.$v3popup({...}) } } // vue3中调用 setup() { // 获取上下文 const { ctx } = getCurrentInstance() ctx.$v3popup({...}) }
通过 方式挂载。
// vue2中调用 methods: { showDialog() { this.v3popup({...}) } } // vue3中调用 setup() { const v3popup = inject(\'v3popup\') const showDialog = () => { v3popup({...}) } return { v3popup, showDialog } }
预览效果
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 层关闭回调事件
vpopop.vue模板核心代码
<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自定义弹出层组件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>
vue2.x中通过Vue.extends扩展函数实例来实现挂载弹窗到body上。
vue3.x中则可以通过 和
来实现挂载到body上。
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) }
这样就可以实现函数式来调用组件了。
另外vue2.x中给v-model传值 this.$emit(\’input\’, false)
vue3中modelValue是默认的。 则是 context.emit(\’update:modelValue\’, false)
如果定义的是v-model:visible,则需要先在props: { visible: Boolean }中声明,然后context.emit(\’update:visible\’: false)
Ok,基于vue3.0开发自定义弹框组件就介绍到这里。感兴趣的可以动手去试试哈。💪🏻
© 版权声明
THE END
暂无评论内容