vue實現(xiàn)點擊出現(xiàn)操作彈出框的示例

如上圖所示,這次要實現(xiàn)一個點擊出現(xiàn)操作彈框的效果;并將這個功能封裝成一個函數(shù),便于在項目的多個地方使用。
具體思路是:
封裝一個組件,組件保護一個插槽,我們可以根據(jù)不同的場景,利用插槽隨意在這個彈框里插入任何元素,這個彈框顯示時根據(jù)我鼠標的點擊位置,定位彈窗的位置,并在組件里面監(jiān)聽鼠標抬起事件,觸發(fā)事件時將彈窗隱藏;
接著在函數(shù)中利用createElement和appendChild方法將彈出框創(chuàng)建并插入到頁面中;
本次實現(xiàn)基于vuecli3
接下來,具體實現(xiàn):
首先,我們先寫一個demo組件
在點擊出現(xiàn)彈出框的元素上把事件對象數(shù)據(jù)傳遞一下,以便獲取點擊時鼠標的數(shù)據(jù),以此確定彈出框的位置
// 文件路徑參考: src > views > demo> index.vue
<template>
<div class="demo-wrapper">
<div class="demo-div">
<span>更多功能</span>
<i class="xk-icon xk-ellipsis" @click.stop='showMenu($event)'></i> // 為了獲取鼠標位置,這里把事件對象數(shù)據(jù)傳遞一下
</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){
// 點擊時出現(xiàn)彈出框
}
};
</script>
接著,我們把彈出框里面的組件也寫一下
組件隨便命名為ActionList,組件里面把把列表數(shù)據(jù)及點擊事件都基于父組件傳遞的值而定,由于只是小demo,所以我們傳遞的menu數(shù)據(jù)數(shù)組只是簡單的字符串數(shù)組
// 文件路徑參考: src > components > ActionList > index.vue<template>
<ul class="menu-wrapper">
<li
class="menu-item"
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';
@Component
export default class ActionList extends Vue {
@Prop() menu: string[];
handleClick(str: string) {
this.$emit('click', str);
}
}
</script>
接著,開始著手寫彈框組件
1、彈框組件的顯示隱藏用v-show控制,為什么不用v-if ?因為這里我監(jiān)聽了mouseup事件來讓彈框隱藏,如果在插槽里的元素綁定事件,比如點擊事件,用v-if 的話,點擊插槽里的元素時,彈框先消失,插槽里的點擊事件就不會生效了。
2、handleOpen事件里我們根據(jù)鼠標點擊位置定位彈框位置。
// 文件路徑參考: src > components > PublicModel > index.vue<template>
<div class="dropdown-menu" :style="style" 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;
}
@Component
export 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)
}
// 隱藏關(guān)閉此組件
closeModel(){
this.showModel = false;
document.removeEventListener('mouseup', this.closeModel);
}
// 組件銷毀生命周期
destroyed(){
document.removeEventListener('mouseup', this.closeModel);
}
}
</script>
接著,重點來了,書寫公用封裝函數(shù)
我們要在demo組件點擊時觸發(fā)這個函數(shù),即在demo組件里的showMenu事件觸發(fā)函數(shù),這個函數(shù)要利用createElement和appendChild方法將彈出框創(chuàng)建并插入到頁面中。
因為是點擊時創(chuàng)建并插入元素,所以為了性能優(yōu)化,避免有惡意瘋狂點擊,不斷創(chuàng)建和插入元素,我們利用throttle-debounce插件做一個節(jié)流。
先直接看代碼,其他注釋寫在了代碼里,函數(shù)名隨意?。篗odelFun
// 文件路徑參考: src > components > PublicModel > index.ts
import 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) => { // 這里兩個參數(shù)一個是彈框里插槽的組件,還有就是點擊的事件對象(方便定位彈框位置)
if(!instance){
initInstance()
}
instance.$slots.default = [slotVNode]; // 將傳遞過來的插槽組件插入彈框組件中
instance.handleOpen($event) // 觸發(fā)彈框組件(見上一段代碼)的彈框獲取定位信息并顯示的事件
}
const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保證在一系列調(diào)用時間中回調(diào)函數(shù)只執(zhí)行一次,這里是200毫秒 // 第二個參數(shù)為false時,在點擊時會在200毫秒后再執(zhí)行callback(即insertInstanceSlot),但為true時,會立即先執(zhí)行一次;
export default ModelFun
接著,重點來了,書寫公用封裝函數(shù)
我們要在demo組件點擊時觸發(fā)這個函數(shù),即在demo組件里的showMenu事件觸發(fā)函數(shù),這個函數(shù)要利用createElement和appendChild方法將彈出框創(chuàng)建并插入到頁面中。
因為是點擊時創(chuàng)建并插入元素,所以為了性能優(yōu)化,避免有惡意瘋狂點擊,不斷創(chuàng)建和插入元素,我們利用throttle-debounce插件做一個節(jié)流。
先直接看代碼,其他注釋寫在了代碼里,函數(shù)名隨意?。篗odelFun
// 文件路徑參考: 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) => { // 這里兩個參數(shù)一個是彈框里插槽的組件,還有就是點擊的事件對象(方便定位彈框位置)
if(!instance){
initInstance()
}
instance.$slots.default = [slotVNode]; // 將傳遞過來的插槽組件插入彈框組件中
instance.handleOpen($event) // 觸發(fā)彈框組件(見上一段代碼)的彈框獲取定位信息并顯示的事件
}
const ModelFun = debounce(200, false, insertInstanceSlot) // 使用throttle-debounce里的debounce保證在一系列調(diào)用時間中回調(diào)函數(shù)只執(zhí)行一次,這里是200毫秒 // 第二個參數(shù)為false時,在點擊時會在200毫秒后再執(zhí)行callback(即insertInstanceSlot),但為true時,會立即先執(zhí)行一次;export default ModelFun
最后,我們回過頭來完善一下demo組件
利用vue的 $createElement 將ActionList組件插入彈框中,并將數(shù)據(jù)和事件傳遞給ActionList組件,這里我們傳遞的事件是簡單的彈出我們點擊的數(shù)據(jù)
// 文件路徑參考: src > views > demo> index.vue<template>
<div class="demo-wrapper">
<div class="demo-div">
<span>更多功能</span>
<i class="xk-icon xk-ellipsis" @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 組件結(jié)合我們封裝的彈框看一下效果
代碼:
<template>
<div class="demo-wrapper">
<el-tree
:data="data"
node-key="id"
:default-expand-all="true"
:expand-on-click-node="false"
show-checkbox
>
<div class="custom-tree-node tree-item" iv slot-scope="{ node }">
<span>{{ node.label }}</span>
<span
class="action"
@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實現(xiàn)點擊出現(xiàn)操作彈出框的示例的詳細內(nèi)容,更多關(guān)于vue 彈出框的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue3+elementUI實現(xiàn)懸浮多行文本輸入框效果
這篇文章主要為大家詳細介紹了vue3如何引用elementUI實現(xiàn)懸浮文本輸入框效果,以便實現(xiàn)多行文本輸入,感興趣的小伙伴可以跟隨小編一起學習一下2023-10-10
非Vuex實現(xiàn)的登錄狀態(tài)判斷封裝實例代碼
這篇文章主要給大家介紹了關(guān)于非Vuex實現(xiàn)的登錄狀態(tài)判斷封裝的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2022-02-02
Vue3.0路由跳轉(zhuǎn)攜帶參數(shù)的示例詳解
這篇文章主要介紹了Vue3.0路由跳轉(zhuǎn)攜帶參數(shù)的示例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
vue 全局封裝loading加載教程(全局監(jiān)聽)
這篇文章主要介紹了vue 全局封裝loading加載教程(全局監(jiān)聽),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11

