vue實現點擊出現操作彈出框的示例
如上圖所示,這次要實現一個點擊出現操作彈框的效果;并將這個功能封裝成一個函數,便于在項目的多個地方使用。
具體思路是:
封裝一個組件,組件保護一個插槽,我們可以根據不同的場景,利用插槽隨意在這個彈框里插入任何元素,這個彈框顯示時根據我鼠標的點擊位置,定位彈窗的位置,并在組件里面監聽鼠標抬起事件,觸發事件時將彈窗隱藏;
接著在函數中利用createElement和appendChild方法將彈出框創建并插入到頁面中;
本次實現基于vuecli3
接下來,具體實現:
首先,我們先寫一個demo組件
在點擊出現彈出框的元素上把事件對象數據傳遞一下,以便獲取點擊時鼠標的數據,以此確定彈出框的位置
// 文件路徑參考: src > views > demo> index.vue<template> <div class='demo-wrapper'> <div class='demo-div'> <span>更多功能</span> <i @click.stop=’showMenu($event)’></i> // 為了獲取鼠標位置,這里把事件對象數據傳遞一下 </div> </div></template><script lang='ts'> import { Vue, Component, Prop, Watch} from 'vue-property-decorator'; @Component({ }) export default class articleView extends Vue { showMenu($event:any){ // 點擊時出現彈出框 } };</script>
接著,我們把彈出框里面的組件也寫一下
組件隨便命名為ActionList,組件里面把把列表數據及點擊事件都基于父組件傳遞的值而定,由于只是小demo,所以我們傳遞的menu數據數組只是簡單的字符串數組
// 文件路徑參考: src > components > ActionList > index.vue<template> <ul class='menu-wrapper'> <li v-for='item in menu' :key='item' @click='handleClick(item)' > {{ item }} </li> </ul></template><script lang='ts'>import { Component, Prop, Vue } from ’vue-property-decorator’;@Componentexport default class ActionList extends Vue { @Prop() menu: string[]; handleClick(str: string) { this.$emit(’click’, str); }}</script>
接著,開始著手寫彈框組件
1、彈框組件的顯示隱藏用v-show控制,為什么不用v-if ?因為這里我監聽了mouseup事件來讓彈框隱藏,如果在插槽里的元素綁定事件,比如點擊事件,用v-if 的話,點擊插槽里的元素時,彈框先消失,插槽里的點擊事件就不會生效了。
2、handleOpen事件里我們根據鼠標點擊位置定位彈框位置。
// 文件路徑參考: src > components > PublicModel > index.vue<template> <div : v-show=’showModel’> <slot></slot> </div></template><script lang='ts'>import { Component, Prop, Vue } from ’vue-property-decorator’;interface IStyle { left?: string; right?: string; top?: string; bottom?: string;}@Componentexport default class PublicModel extends Vue { showModel:boolean = false; style:IStyle = {}; // 組件顯示時 handleOpen($event:any){ const { clientWidth, clientHeight, scrollWidth, scrollHeight } = document.body || document.documentElement; const { pageX, pageY, clientX, clientY } = $event; let style:IStyle = {} if(clientX > (clientWidth * 2)/3 ){ style.right = scrollWidth - pageX + 10 + ’px’; }else{ style.left = pageX+10+’px’ } if(clientY > (clientHeight * 2) / 3 ){ style.bottom = scrollHeight - pageY + 10 + ’px’; }else{ style.top = pageY + 10 + 'px' } this.style = style; this.showModel = true; document.addEventListener(’mouseup’,this.closeModel) } // 隱藏關閉此組件 closeModel(){ this.showModel = false; document.removeEventListener(’mouseup’, this.closeModel); } // 組件銷毀生命周期 destroyed(){ document.removeEventListener(’mouseup’, this.closeModel); }}</script>
接著,重點來了,書寫公用封裝函數
我們要在demo組件點擊時觸發這個函數,即在demo組件里的showMenu事件觸發函數,這個函數要利用createElement和appendChild方法將彈出框創建并插入到頁面中。
因為是點擊時創建并插入元素,所以為了性能優化,避免有惡意瘋狂點擊,不斷創建和插入元素,我們利用throttle-debounce插件做一個節流。
先直接看代碼,其他注釋寫在了代碼里,函數名隨意取:ModelFun
// 文件路徑參考: src > components > PublicModel > index.tsimport Vue from ’vue’;import PublicModel from ’./index.vue’; // 導入上面所寫的彈框組件const throttleDebounce = require(’throttle-debounce’); // throttle-debounce插件const debounce = throttleDebounce.debounce;const PublicModelConstructor = Vue.extend(PublicModel);let instance:any;const initInstance = () => { instance = new PublicModelConstructor({ el: document.createElement(’div’), }); document.body.appendChild(instance.$el);}const insertInstanceSlot = (slotVNode:any, $event:any) => { // 這里兩個參數一個是彈框里插槽的組件,還有就是點擊的事件對象(方便定位彈框位置) if(!instance){ initInstance() } instance.$slots.default = [slotVNode]; // 將傳遞過來的插槽組件插入彈框組件中 instance.handleOpen($event) // 觸發彈框組件(見上一段代碼)的彈框獲取定位信息并顯示的事件}const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保證在一系列調用時間中回調函數只執行一次,這里是200毫秒 // 第二個參數為false時,在點擊時會在200毫秒后再執行callback(即insertInstanceSlot),但為true時,會立即先執行一次;export default ModelFun
接著,重點來了,書寫公用封裝函數
我們要在demo組件點擊時觸發這個函數,即在demo組件里的showMenu事件觸發函數,這個函數要利用createElement和appendChild方法將彈出框創建并插入到頁面中。
因為是點擊時創建并插入元素,所以為了性能優化,避免有惡意瘋狂點擊,不斷創建和插入元素,我們利用throttle-debounce插件做一個節流。
先直接看代碼,其他注釋寫在了代碼里,函數名隨意取:ModelFun
// 文件路徑參考: src > components > PublicModel > index.tsimport Vue from ’vue’;import PublicModel from ’./index.vue’; // 導入上面所寫的彈框組件const throttleDebounce = require(’throttle-debounce’); // throttle-debounce插件const debounce = throttleDebounce.debounce;const PublicModelConstructor = Vue.extend(PublicModel);let instance:any;const initInstance = () => { instance = new PublicModelConstructor({ el: document.createElement(’div’), }); document.body.appendChild(instance.$el);}const insertInstanceSlot = (slotVNode:any, $event:any) => { // 這里兩個參數一個是彈框里插槽的組件,還有就是點擊的事件對象(方便定位彈框位置) if(!instance){ initInstance() } instance.$slots.default = [slotVNode]; // 將傳遞過來的插槽組件插入彈框組件中 instance.handleOpen($event) // 觸發彈框組件(見上一段代碼)的彈框獲取定位信息并顯示的事件}const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保證在一系列調用時間中回調函數只執行一次,這里是200毫秒 // 第二個參數為false時,在點擊時會在200毫秒后再執行callback(即insertInstanceSlot),但為true時,會立即先執行一次;export default ModelFun
最后,我們回過頭來完善一下demo組件
利用vue的 $createElement 將ActionList組件插入彈框中,并將數據和事件傳遞給ActionList組件,這里我們傳遞的事件是簡單的彈出我們點擊的數據
// 文件路徑參考: src > views > demo> index.vue<template> <div class='demo-wrapper'> <div class='demo-div'> <span>更多功能</span> <i @click.stop=’showMenu($event)’></i> </div> </div></template><script lang='ts'> import { Vue, Component, Prop, Watch} from 'vue-property-decorator'; import ActionList from '@/components/ActionList/index.vue'; import modelFun from '@/components/PublicModel/index'; @Component({ }) export default class articleView extends Vue { menuList: string[] = [’菜單1’,’菜單2’,’菜單3’]; menuClick(name:string){ // 彈框里插槽的點擊事件 this.$message({message:name,type:’success’}) } showMenu($event:any){ modelFun(this.$createElement( ActionList, { props: { menu:this.menuList }, on:{ click: this.menuClick, } }),$event ) } };</script>
至此,效果如下
最后,我們利用element ui 的 tree 組件結合我們封裝的彈框看一下效果代碼:
<template> <div class='demo-wrapper'> <el-tree:data='data' node-key='id':default-expand-all='true' :expand-on-click-node='false' show-checkbox ><div iv slot-scope='{ node }'> <span>{{ node.label }}</span> <span @click.stop='showMenu($event)' > <i class='el-icon-more'></i> </span></div> </el-tree> </div></template><script lang='ts'> import { Vue, Component, Prop, Watch} from 'vue-property-decorator'; import ActionList from '@/components/ActionList/index.vue'; import modelFun from '@/components/PublicModel/index'; @Component({ }) export default class articleView extends Vue { menuList: string[] = [’菜單1’,’菜單2’,’菜單3’]; data:any[] = [{ id: 1, label: ’一級 1’, children: [{ id: 4, label: ’二級 1-1’, children: [{ id: 9, label: ’三級 1-1-1’ }, { id: 10, label: ’三級 1-1-2’ }] }] }, { id: 2, label: ’一級 2’, children: [{ id: 5, label: ’二級 2-1’ }, { id: 6, label: ’二級 2-2’ }] }, { id: 3, label: ’一級 3’, children: [{ id: 7, label: ’二級 3-1’ }, { id: 8, label: ’二級 3-2’ }] }]; menuClick(name:string){ console.log(name) this.$message({message:name,type:’success’}) } showMenu($event:any){ modelFun(this.$createElement( ActionList, { props: { menu:this.menuList }, on:{ click: this.menuClick, } }),$event ) } };</script>
效果:
以上就是vue實現點擊出現操作彈出框的示例的詳細內容,更多關于vue 彈出框的資料請關注好吧啦網其它相關文章!
相關文章: