1. 程式人生 > 程式設計 >vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

Vue3-Popup 基於vue3構建的手機端自定義彈層元件。

一款集合了msg、alert、dialog、modal、actionSheet、toast等多種效果的Vue3自定義彈層元件。支援上下左右彈出、圓角、自定義彈層樣式、多按鈕及長按/右鍵功能。

vue3彈出層V3Popup例項詳解

引入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: '確認',click: () => handleOK},],onSuccess: () => {},onEnd: () => {}
})

vue3彈出層V3Popup例項詳解

vue3中可通過app.config.globalPropertiesapp.provide

兩種方式掛載類似vue2中prototype原型鏈方法。

通過vue3彈出層V3Popup例項詳解方式掛載。

// vue2中呼叫
methods: {
 showDialog() {
  this.$v3popup({...})
 }
}
 
// vue3中呼叫
setup() {
 // 獲取上下文
 const { ctx } = getCurrentInstance()
 ctx.$v3popup({...})
}

通過vue3彈出層V3Popup例項詳解方式掛載。

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

預覽效果

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

vue3彈出層V3Popup例項詳解

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   層關閉回撥事件

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,opacity: { type: [Number,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,default: 0 },zIndex: { type: [Number,default: '8080' },teleport: [String,Object],btns: {
    type: Array,default: null
   },onSuccess: { type: Function,onEnd: { type: Function,},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中則可以通過 createAppcreateVNode render來實現掛載到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開發自定義彈框元件就介紹到這裡。感興趣的可以動手去試試哈。💪🏻

到此這篇關於vue3彈出層V3Popup例項詳解的文章就介紹到這了,更多相關vue3彈出層內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!