欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3自定義dialog、modal組件的方法

 更新時(shí)間:2021年01月04日 11:40:25   作者:xiaoyan_2018  
這篇文章主要介紹了vue3自定義dialog、modal組件的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

vue3-layer:基于Vue3.0開發(fā)的PC桌面端自定義對話框組件。

基于vue3構(gòu)建的PC網(wǎng)頁端自定義彈出框組件。全面覆蓋各種彈窗應(yīng)用場景,擁有10+種彈窗類型、30+種自定義參數(shù)配置、7+種彈窗動(dòng)畫效果,支持拖拽、縮放、最大化、全屏及自定義激活當(dāng)前置頂層等功能。

前幾天分享過一個(gè)Vue3.0移動(dòng)端彈層組件V3Popup,如果感興趣也可以去看看。

http://www.dbjr.com.cn/article/203415.htm

v3layer在開發(fā)設(shè)計(jì)之初靈感來自有贊Vant3.0、餓了么Element-Plus等組件化模式。

快速引入

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

import { createApp } from 'vue'
import App from './App.vue'
 
// 引入Element-Plus組件庫
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
 
// 引入彈窗組件v3layer
import V3Layer from './components/v3layer'
 
createApp(App).use(ElementPlus).use(V3Layer).mount('#app')

v3layer在調(diào)用上同樣支持組件式+函數(shù)式兩種方式。

組件寫法

<v3-layer 
 v-model="showAlert"
 title="標(biāo)題信息"
 content="<div style='color:#f57b16;padding:30px;'>這里是內(nèi)容信息!</div>"
 z-index="2030"
 lockScroll="false"
 xclose
 resize
 dragOut
 :btns="[
  {text: '取消', click: () => showAlert=false},
  {text: '確認(rèn)', style: 'color:#f90;', click: handleConfirm},
 ]"
/>
 <template #content>自定義插槽內(nèi)容信息!</template>
</v3-layer>

 

函數(shù)寫法

let $el = v3layer({
 title: '標(biāo)題信息',
 content: '<div style='color:#ff5252;padding:50px;'>這里是內(nèi)容信息!</div>', 
 shadeClose: false,
 zIndex: 2030,
 lockScroll: false,
 xclose: true,
 resize: true,
 dragOut: true,
 btns: [
  {text: '取消', click: () => { $el.close() }},
  {text: '確認(rèn)', click: () => handleConfirm},
 ]
});

遵循極簡的調(diào)用原則,只需輸入?yún)?shù)配置即可快速調(diào)用彈窗,實(shí)現(xiàn)想要的效果。

參數(shù)配置

v3layer支持如下30+自定義參數(shù)配置,靈活搭配出各種效果。

|props參數(shù)|
v-model   是否顯示彈框
id    彈窗唯一標(biāo)識(shí)
title   標(biāo)題
content   內(nèi)容(支持String、帶標(biāo)簽內(nèi)容、自定義插槽內(nèi)容)***如果content內(nèi)容比較復(fù)雜,推薦使用標(biāo)簽式寫法
type   彈框類型(toast|footer|actionsheet|actionsheetPicker|android|ios|contextmenu|drawer|iframe)
layerStyle  自定義彈窗樣式
icon   toast圖標(biāo)(loading | success | fail)
shade   是否顯示遮罩層
shadeClose  是否點(diǎn)擊遮罩時(shí)關(guān)閉彈窗
lockScroll  是否彈窗出現(xiàn)時(shí)將body滾動(dòng)鎖定
opacity   遮罩層透明度
xclose   是否顯示關(guān)閉圖標(biāo)
xposition  關(guān)閉圖標(biāo)位置(left | right | top | bottom)
xcolor   關(guān)閉圖標(biāo)顏色
anim   彈窗動(dòng)畫(scaleIn | fadeIn | footer | fadeInUp | fadeInDown | fadeInLeft | fadeInRight)
position  彈出位置(auto | ['100px','50px'] | t | r | b | l | lt | rt | lb | rb)
drawer   抽屜彈窗(top | right | bottom | left)
follow   跟隨元素定位彈窗(支持元素.kk #kk 或 [e.clientX, e.clientY])
time   彈窗自動(dòng)關(guān)閉秒數(shù)(1、2、3)
zIndex   彈窗層疊(默認(rèn)8080)
teleport  指定掛載節(jié)點(diǎn)(默認(rèn)是掛載組件標(biāo)簽位置,可通過teleport自定義掛載位置) teleport="body | #xxx | .xxx"
topmost   置頂當(dāng)前窗口(默認(rèn)false)
area   彈窗寬高(默認(rèn)auto)設(shè)置寬度area: '300px' 設(shè)置高度area:['', '200px'] 設(shè)置寬高area:['350px', '150px']
maxWidth  彈窗最大寬度(只有當(dāng)area:'auto'時(shí),maxWidth的設(shè)定才有效)
maximize  是否顯示最大化按鈕(默認(rèn)false)
fullscreen  全屏彈窗(默認(rèn)false)
fixed   彈窗是否固定
drag   拖拽元素(可定義選擇器drag:'.xxx' | 禁止拖拽drag:false)
dragOut   是否允許拖拽到窗口外(默認(rèn)false)
lockAxis  限制拖拽方向可選: v 垂直、h 水平,默認(rèn)不限制
resize   是否允許拉伸尺寸(默認(rèn)false)
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)事件

v3layer彈窗模板及邏輯處理。

<template>
 <div ref="elRef" v-show="opened" class="vui__layer" :class="{'vui__layer-closed': closeCls}" :id="id">
  <!-- //蒙版 -->
  <div v-if="JSON.parse(shade)" class="vlayer__overlay" @click="shadeClicked" :style="{opacity}"></div>
  <div class="vlayer__wrap" :class="['anim-'+anim, type&&'popui__'+type, tipArrow]" :style="[layerStyle]">
   <div v-if="title" class="vlayer__wrap-tit" v-html="title"></div>
   <div v-if="type=='toast'&&icon" class="vlayer__toast-icon" :class="['vlayer__toast-'+icon]" v-html="toastIcon[icon]"></div>
   <div class="vlayer__wrap-cntbox">
    <!-- 判斷插槽是否存在 -->
    <template v-if="$slots.content">
     <div class="vlayer__wrap-cnt"><slot name="content" /></div>
    </template>
    <template v-else>
     <template v-if="content">
      <iframe v-if="type=='iframe'" scrolling="auto" allowtransparency="true" frameborder="0" :src="content"></iframe>
      <!-- message|notify|popover -->
      <div v-else-if="type=='message' || type=='notify' || type=='popover'" class="vlayer__wrap-cnt">
       <i v-if="icon" class="vlayer-msg__icon" :class="icon" v-html="messageIcon[icon]"></i>
       <div class="vlayer-msg__group"><div v-if="title" class="vlayer-msg__title" v-html="title"></div><div v-html="content"></div></div>
      </div>
      <div v-else class="vlayer__wrap-cnt" v-html="content"></div>
     </template>
    </template>
    <slot />
   </div>
   <div v-if="btns" class="vlayer__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="vlayer__xclose" :class="!maximize&&xposition" :style="{'color': xcolor}" @click="close"></span>
   <span v-if="maximize" class="vlayer__maximize" @click="maximizeClicked($event)"></span>
   <span v-if="resize" class="vlayer__resize"></span>
  </div>
  <!-- 優(yōu)化拖拽卡頓 -->
  <div class="vlayer__dragfix"></div>
 </div>
</template>
 
/**
 * @Desc  Vue3.0桌面端彈窗組件V3Layer
 * @Time  andy by 2021-1
 * @About Q:282310962 wx:xy190310
 */
<script>
 import { onMounted, onUnmounted, ref, reactive, watch, toRefs, nextTick } from 'vue'
 import domUtils from './utils/dom.js'
 // 索引,蒙層控制,定時(shí)器
 let $index = 0, $locknum = 0, $timer = {}, $closeTimer = null
 export default {
  props: {
   // ...
  },
  emits: [
   'update:modelValue'
  ],
  setup(props, context) {
   const elRef = ref(null);
 
   const data = reactive({
    opened: false,
    closeCls: '',
    toastIcon: {
     // ...
    },
    messageIcon: {
     // ...
    },
    vlayerOpts: {},
    tipArrow: null,
   })
 
   onMounted(() => {
    if(props.modelValue) {
     open();
    }
    window.addEventListener('resize', autopos, false);
   })
 
   onUnmounted(() => {
    window.removeEventListener('resize', autopos, false);
    clearTimeout($closeTimer);
   })
 
   // 監(jiān)聽彈層v-model
   watch(() => props.modelValue, (val) => {
    // console.log('V3Layer is now [%s]', val ? 'show' : 'hide')
    if(val) {
     open();
    }else {
     close();
    }
   })
 
   // 打開彈窗
   const open = () => {
    if(data.opened) return;
    data.opened = true;
    typeof props.onSuccess === 'function' && props.onSuccess();
 
    const dom = elRef.value;
    // 彈層掛載位置
    if(props.teleport) {
     nextTick(() => {
      let teleportNode = document.querySelector(props.teleport);
      teleportNode.appendChild(dom);
 
      auto();
     })
    }
 
    callback();
   }
 
   // 關(guān)閉彈窗
   const close = () => {
    if(!data.opened) return;
 
    let dom = elRef.value;
    let vlayero = dom.querySelector('.vlayer__wrap');
    let ocnt = dom.querySelector('.vlayer__wrap-cntbox');
    let omax = dom.querySelector('.vlayer__maximize');
 
    data.closeCls = true;
    clearTimeout($closeTimer);
    $closeTimer = setTimeout(() => {
     data.opened = false;
     data.closeCls = false;
     if(data.vlayerOpts.lockScroll) {
      $locknum--;
      if(!$locknum) {
       document.body.style.paddingRight = '';
       document.body.classList.remove('vui__body-hidden');
      }
     }
     if(props.time) {
      $index--;
     }
     // 清除彈窗樣式
     vlayero.style.width = vlayero.style.height = vlayero.style.top = vlayero.style.left = '';
     ocnt.style.height = '';
     omax && omax.classList.contains('maximized') && omax.classList.remove('maximized');
     
     data.vlayerOpts.isBodyOverflow && (document.body.style.overflow = '');
 
     context.emit('update:modelValue', false);
     typeof props.onEnd === 'function' && props.onEnd();
    }, 200)
   }
 
   // 彈窗位置
   const auto = () => {
    // ...
 
    autopos();
 
    // 全屏彈窗
    if(props.fullscreen) {
     full();
    }
 
    // 彈窗拖動(dòng)|縮放
    move();
   }
 
   const autopos = () => {
    if(!data.opened) return;
    let oL, oT
    let pos = props.position;
    let isFixed = JSON.parse(props.fixed);
    let dom = elRef.value;
    let vlayero = dom.querySelector('.vlayer__wrap');
 
    if(!isFixed || props.follow) {
     vlayero.style.position = 'absolute';
    }
    
    let area = [domUtils.client('width'), domUtils.client('height'), vlayero.offsetWidth, vlayero.offsetHeight]
    
    oL = (area[0] - area[2]) / 2;
    oT = (area[1] - area[3]) / 2;
 
    if(props.follow) {
     offset();
    }else {
     typeof pos === 'object' ? (
      oL = parseFloat(pos[0]) || 0, oT = parseFloat(pos[1]) || 0
     ) : (
      pos == 't' ? oT = 0 : 
      pos == 'r' ? oL = area[0] - area[2] : 
      pos == 'b' ? oT = area[1] - area[3] : 
      pos == 'l' ? oL = 0 : 
      pos == 'lt' ? (oL = 0, oT = 0) : 
      pos == 'rt' ? (oL = area[0] - area[2], oT = 0) : 
      pos == 'lb' ? (oL = 0, oT = area[1] - area[3]) :
      pos == 'rb' ? (oL = area[0] - area[2], oT = area[1] - area[3]) : 
      null
     )
 
     vlayero.style.left = parseFloat(isFixed ? oL : domUtils.scroll('left') + oL) + 'px';
     vlayero.style.top = parseFloat(isFixed ? oT : domUtils.scroll('top') + oT) + 'px';
    }
   }
 
   // 元素跟隨定位
   const offset = () => {
    let oW, oH, pS
    let dom = elRef.value
    let vlayero = dom.querySelector('.vlayer__wrap');
 
    oW = vlayero.offsetWidth;
    oH = vlayero.offsetHeight;
    pS = domUtils.getFollowRect(props.follow, oW, oH);
    data.tipArrow = pS[2];
    
    vlayero.style.left = pS[0] + 'px';
    vlayero.style.top = pS[1] + 'px';
   }
 
   // 最大化彈窗
   const full = () => {
    // ...
   }
 
   // 恢復(fù)彈窗
   const restore = () => {
    let dom = elRef.value;
    let vlayero = dom.querySelector('.vlayer__wrap');
    let otit = dom.querySelector('.vlayer__wrap-tit');
    let ocnt = dom.querySelector('.vlayer__wrap-cntbox');
    let obtn = dom.querySelector('.vlayer__wrap-btns');
    let omax = dom.querySelector('.vlayer__maximize');
 
    let t = otit ? otit.offsetHeight : 0
    let b = obtn ? obtn.offsetHeight : 0
 
    if(!data.vlayerOpts.lockScroll) {
     data.vlayerOpts.isBodyOverflow = false;
     document.body.style.overflow = '';
    }
    
    props.maximize && omax.classList.remove('maximized')
    
    vlayero.style.left = parseFloat(data.vlayerOpts.rect[0]) + 'px';
    vlayero.style.top = parseFloat(data.vlayerOpts.rect[1]) + 'px';
    vlayero.style.width = parseFloat(data.vlayerOpts.rect[2]) + 'px';
    vlayero.style.height = parseFloat(data.vlayerOpts.rect[3]) + 'px';
   }
 
   // 拖動(dòng)|縮放彈窗
   const move = () => {
    // ...
   }
 
   // 事件處理
   const callback = () => {
    // 倒計(jì)時(shí)關(guān)閉
    if(props.time) {
     $index++
     // 防止重復(fù)點(diǎn)擊
     if($timer[$index] !== null) clearTimeout($timer[$index])
     $timer[$index] = setTimeout(() => {
      close();
     }, parseInt(props.time) * 1000)
    }
   }
 
   // 點(diǎn)擊最大化按鈕
   const maximizeClicked = (e) => {
    let o = e.target
    if(o.classList.contains('maximized')) {
     // 恢復(fù)
     restore();
    } else {
     // 最大化
     full();
    }
   }
   // 點(diǎn)擊遮罩層
   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,
    maximizeClicked,
    shadeClicked,
    btnClicked,
   }
  }
 }
</script>

大家如果感興趣,可以在此基礎(chǔ)上自行定制一些想要的效果。

另外,v3layer組件支持自定義拖拽區(qū)域 (drag:'class或id'),是否拖動(dòng)到窗口外 (dragOut:true)。支持iframe彈窗類型 (type:'iframe')。

當(dāng)配置 topmost:true 則會(huì)將當(dāng)前活動(dòng)窗口置頂顯示。

好了,基于vue3.x開發(fā)自定義彈窗組件就介紹到這里。希望大家能喜歡~~💪🏻

到此這篇關(guān)于vue3自定義dialog、modal組件的方法的文章就介紹到這了,更多相關(guān)vue 自定義dialog、modal組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Element輸入框帶歷史查詢記錄的實(shí)現(xiàn)示例

    Element輸入框帶歷史查詢記錄的實(shí)現(xiàn)示例

    這篇文章主要介紹了Element輸入框帶歷史查詢記錄的實(shí)現(xiàn)示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • vue之?dāng)?shù)據(jù)交互實(shí)例代碼

    vue之?dāng)?shù)據(jù)交互實(shí)例代碼

    本篇文章主要介紹了vue之?dāng)?shù)據(jù)交互實(shí)例代碼,vue中也存在像ajax和jsonp的數(shù)據(jù)交互,實(shí)現(xiàn)向服務(wù)器獲取數(shù)據(jù),有興趣的可以了解一下
    2017-06-06
  • 淺談vue 二級(jí)路由嵌套和二級(jí)路由高亮問題

    淺談vue 二級(jí)路由嵌套和二級(jí)路由高亮問題

    這篇文章主要介紹了淺談vue 二級(jí)路由嵌套和二級(jí)路由高亮問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Vue實(shí)現(xiàn)電商網(wǎng)站商品放大鏡效果示例

    Vue實(shí)現(xiàn)電商網(wǎng)站商品放大鏡效果示例

    這篇文章主要為大家介紹了Vue實(shí)現(xiàn)電商網(wǎng)站商品放大鏡效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊

    vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊

    這篇文章主要介紹了vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • element-ui修改el-form-item樣式的詳細(xì)示例

    element-ui修改el-form-item樣式的詳細(xì)示例

    在使用element-ui組件庫的時(shí)候經(jīng)常需要修改原有樣式,下面這篇文章主要給大家介紹了關(guān)于element-ui修改el-form-item樣式的詳細(xì)示例,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • vue路由權(quán)限和按鈕權(quán)限的實(shí)現(xiàn)示例

    vue路由權(quán)限和按鈕權(quán)限的實(shí)現(xiàn)示例

    本文主要介紹了vue路由權(quán)限和按鈕權(quán)限的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Vue3中使用echarts的簡單七個(gè)步驟(易懂,附緊急避坑)

    Vue3中使用echarts的簡單七個(gè)步驟(易懂,附緊急避坑)

    近期在做一個(gè)vue3的項(xiàng)目,里面有個(gè)圖表需求,因公司之前使用第三方封裝的圖表缺少文檔,就去看了echars的官網(wǎng)文檔,引入原生echars來實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Vue3中使用echarts的簡單七個(gè)步驟,需要的朋友可以參考下
    2023-01-01
  • ElementUI 修改默認(rèn)樣式的幾種辦法(小結(jié))

    ElementUI 修改默認(rèn)樣式的幾種辦法(小結(jié))

    這篇文章主要介紹了ElementUI 修改默認(rèn)樣式的幾種辦法(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • vue.nextTick()與setTimeout的區(qū)別及說明

    vue.nextTick()與setTimeout的區(qū)別及說明

    這篇文章主要介紹了vue.nextTick()與setTimeout的區(qū)別及說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評論