vue3彈出層V3Popup實例詳解
Vue3-Popup 基于vue3構(gòu)建的手機端自定義彈層組件。
一款集合了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')
調(diào)用方式支持標簽式+函數(shù)式,根據(jù)項目需要選擇合適的調(diào)用方法。
<!-- 提示框 -->
<v3-popup v-model="showMsg" anim="fadeIn" content="msg提示框測試(3s后窗口關(guān)閉)" 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},
]"
/>
// 函數(shù)式調(diào)用
let $el = this.$v3popup({
title: '標題',
content: '<div style='color:#f90;padding:10px;'>這里是內(nèi)容信息!</div>',
type: 'android',
shadeClose: false,
xclose: true,
btns: [
{text: '取消', click: () => { $el.close(); }},
{text: '確認', style: 'color:#f90;', click: () => handleOK},
],
onSuccess: () => {},
onEnd: () => {}
})

vue3中可通過
和
兩種方式掛載類似vue2中prototype原型鏈方法。
通過
方式掛載。
// vue2中調(diào)用
methods: {
showDialog() {
this.$v3popup({...})
}
}
// vue3中調(diào)用
setup() {
// 獲取上下文
const { ctx } = getCurrentInstance()
ctx.$v3popup({...})
}
通過
方式掛載。
// vue2中調(diào)用
methods: {
showDialog() {
this.v3popup({...})
}
}
// vue3中調(diào)用
setup() {
const v3popup = inject('v3popup')
const showDialog = () => {
v3popup({...})
}
return {
v3popup,
showDialog
}
}
預覽效果








v3popup參數(shù)配置
組件支持如下20+種參數(shù)靈活配置。
|props參數(shù)| v-model 是否顯示彈框 title 標題 content 內(nèi)容(支持String、帶標簽內(nèi)容、自定義插槽內(nèi)容)***如果content內(nèi)容比較復雜,推薦使用標簽式寫法 type 彈窗類型(toast | footer | actionsheet | actionsheetPicker | android | ios) popupStyle 自定義彈窗樣式 icon toast圖標(loading | success | fail) shade 是否顯示遮罩層 shadeClose 是否點擊遮罩時關(guān)閉彈窗 opacity 遮罩層透明度 round 是否顯示圓角 xclose 是否顯示關(guān)閉圖標 xposition 關(guān)閉圖標位置(left | right | top | bottom) xcolor 關(guān)閉圖標顏色 anim 彈窗動畫(scaleIn | fadeIn | footer | fadeInUp | fadeInDown) position 彈出位置(top | right | bottom | left) follow 長按/右鍵彈窗(坐標點) time 彈窗自動關(guān)閉秒數(shù)(1、2、3) zIndex 彈窗層疊(默認8080) teleport 指定掛載節(jié)點(默認是掛載組件標簽位置,可通過teleport自定義掛載位置) teleport="body | #xxx | .xxx" btns 彈窗按鈕(參數(shù):text|style|disabled|click) ++++++++++++++++++++++++++++++++++++++++++++++ |emit事件觸發(fā)| success 層彈出后回調(diào)(@success="xxx") end 層銷毀后回調(diào)(@end="xxx") ++++++++++++++++++++++++++++++++++++++++++++++ |event事件| onSuccess 層打開回調(diào)事件 onEnd 層關(guān)閉回調(diào)事件
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(() => {
...
})
// 監(jiān)聽彈層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) {
...
}
}
// 關(guān)閉彈層
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擴展函數(shù)實例來實現(xiàn)掛載彈窗到body上。
vue3.x中則可以通過
和
來實現(xiàn)掛載到body上。
import { createApp } from 'vue'
import PopupConstructor from './popup.vue'
let $inst
// 創(chuàng)建掛載實例
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)
}
這樣就可以實現(xiàn)函數(shù)式來調(diào)用組件了。
另外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開發(fā)自定義彈框組件就介紹到這里。感興趣的可以動手去試試哈。💪🏻
到此這篇關(guān)于vue3彈出層V3Popup實例詳解的文章就介紹到這了,更多相關(guān)vue3彈出層內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入探索VueJS Scoped CSS 實現(xiàn)原理
這篇文章主要介紹了深入探索VueJS Scoped CSS 實現(xiàn)原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09
Vue.js bootstrap前端實現(xiàn)分頁和排序
這篇文章主要為大家詳細介紹了Vue.js結(jié)合bootstrap前端實現(xiàn)分頁和排序效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
webpack4+express+mongodb+vue實現(xiàn)增刪改查的示例
這篇文章主要介紹了webpack4+express+mongodb+vue 實現(xiàn)增刪改查的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
關(guān)于Vue3中element-plus的el-dialog對話框無法顯示的問題及解決方法
最近今天在寫一個停車場管理系統(tǒng)的項目時,在用vue3寫前端時,在前端模板選擇上,我一時腦抽,突然決定放棄SpringBoot,選擇了以前幾乎很少用的element-plus,然后果不其然,錯誤連連,下面給大家分享dialog對話框無法顯示的原因,感興趣的朋友一起看看吧2023-10-10
vue-cli如何修改打包項目結(jié)構(gòu)及前綴
這篇文章主要介紹了vue-cli如何修改打包項目結(jié)構(gòu)及前綴問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07

