使用Vue封裝一個自定義的右鍵菜單組件
說在前面
網(wǎng)頁的功能和用途可能各不相同,在傳統(tǒng)右鍵菜單欄中無法滿足每個用戶的個性化需求。通過自定義右鍵菜單欄,用戶可以根據(jù)自己的需求添加、調(diào)整和刪除菜單選項,以實現(xiàn)個性化定制。通過自定義右鍵菜單欄,可以為用戶提供快速訪問常用功能和操作的便捷方式,從而提高用戶體驗。
效果展示
實現(xiàn)原理
1、oncontextmenu事件了解一下
oncontextmenu 事件在元素中用戶右擊鼠標(biāo)時觸發(fā)并打開上下文菜單。
oncontextmenu是一個DOM事件,它在用戶右鍵點擊時觸發(fā)??梢酝ㄟ^在HTML元素上添加oncontextmenu屬性來指定右鍵菜單的處理函數(shù)。
例如,在一個按鈕元素上添加oncontextmenu屬性:
<button oncontextmenu="showContextMenu(event)">右鍵點擊我</button>
在這個示例中,當(dāng)用戶右鍵點擊按鈕時,會調(diào)用showContextMenu函數(shù),并將事件對象作為參數(shù)傳遞給該函數(shù)。
在JavaScript代碼中,可以定義showContextMenu函數(shù)來處理右鍵菜單的顯示和操作:
function showContextMenu(event) { event.preventDefault(); // 阻止默認(rèn)的右鍵菜單彈出 // 顯示自定義右鍵菜單 // ... }
在showContextMenu函數(shù)中,通過調(diào)用event.preventDefault()方法阻止瀏覽器默認(rèn)的右鍵菜單彈出。然后,可以根據(jù)需要執(zhí)行自定義的邏輯,例如顯示自定義的右鍵菜單。
2、在指定容器元素自定義右鍵菜單
首先,使用getElementById方法獲取綁定右鍵菜單的DOM元素和右鍵菜單的容器元素。如果獲取失敗,則直接返回。
const dom = document.getElementById(this.domId); if (!dom) return;
接著,給綁定右鍵菜單的DOM元素添加oncontextmenu事件處理函數(shù)。當(dāng)用戶觸發(fā)右鍵點擊事件時,首先調(diào)用hideAllMenu方法隱藏所有的右鍵菜單,然后通過event.preventDefault方法禁止默認(rèn)行為,防止瀏覽器彈出默認(rèn)的右鍵菜單。接下來,計算出鼠標(biāo)指針相對于文檔頂部和左側(cè)的位置,并設(shè)置右鍵菜單的位置和顯示狀態(tài)。
const that = this; dom.oncontextmenu = function (e) { that.hideAllMenu(that.uid); // 自定義body元素的鼠標(biāo)事件處理函數(shù) e = e || window.event; e.preventDefault(); let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 獲取垂直滾動條位置 let scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; // 獲取水平滾動條位置 menu.style.display = "block"; menu.style.left = e.clientX + scrollLeft + "px"; menu.style.top = e.clientY + scrollTop + "px"; };
最后,給document對象添加onclick事件處理函數(shù)。當(dāng)用戶在其他位置點擊鼠標(biāo)時,調(diào)用hideAllMenu方法隱藏所有的右鍵菜單。
document.onclick = function () { that.hideAllMenu(); }; hideAllMenu(id) { const jMenu = document.getElementsByClassName("j-mouse-menu"); for (let i = 0; i < jMenu.length; i++) { if (jMenu[i].id != id) jMenu[i].style.display = "none"; } },
3、封裝成一個組件
(1)template菜單模板
<div :id="uid" class="j-mouse-menu"> <slot name="header"></slot> <ul> <li v-for="menuItem in menu" :key="menuItem.id" @click="menuClick(menuItem)" > {{ menuItem.label }} </li> </ul> <slot name="body"></slot> <slot name="footer"></slot> </div>
使用:id="uid"
綁定了組件的id屬性,該屬性值由組件實例的uid屬性提供。這樣可以確保每個組件實例都有唯一的id。
然后,給組件添加了j-mouse-menu
類,用于設(shè)置組件的樣式。
在組件的內(nèi)容區(qū)域中,使用了Vue的插槽機制。
<slot name="header"></slot>
定義了一個名為"header"
的插槽,用于放置菜單欄的頭部內(nèi)容。<ul>
標(biāo)簽下使用了v-for
指令遍歷menu
數(shù)組,生成菜單項。- 菜單項使用
<li>
標(biāo)簽表示,并通過:key
綁定了唯一的menuItem.id
作為key值。 - 通過
@click
綁定了menuClick
方法,該方法會在點擊菜單項時被調(diào)用。 - 菜單項的顯示文本使用插值語法
{{ menuItem.label }}
來動態(tài)顯示。
接下來,又定義了兩個插槽:
<slot name="body"></slot>
用于放置菜單欄的主體內(nèi)容。<slot name="footer"></slot>
用于放置菜單欄的底部內(nèi)容。
(2)props入?yún)?/strong>
props: { domId: { type: String, default: "", }, menu: { type: Array, default: () => { return []; }, }, },
domId表示需要綁定右鍵菜單的DOM元素容器的id,menu表示右鍵菜單的選項列表,menu數(shù)據(jù)格式如下:
[ { id: "1", label: "菜單1" }, { id: "2", label: "菜單2", click: this.test }, { id: "3", label: "菜單3" }, { id: "4", label: "菜單4" }, { id: "5", label: "菜單5" } ]
(3)菜單點擊回調(diào)
menuClick(item) { if (item.click) { item.click(item); return; } this.$emit("menuClick", item); },
首先判斷item對象是否存在click屬性。如果存在,則執(zhí)行item.click(item),并將item作為參數(shù)傳遞給click函數(shù)。然后,返回結(jié)束方法的執(zhí)行。
如果item對象不存在click屬性,即沒有自定義的點擊處理函數(shù),那么就通過this.$emit("menuClick", item)語法觸發(fā)一個名為"menuClick"的自定義事件,并將item作為參數(shù)傳遞給父組件。
(4)完整組件代碼
<template> <div> <div :id="uid" class="j-mouse-menu"> <slot name="header"></slot> <ul> <li v-for="menuItem in menu" :key="menuItem.id" @click="menuClick(menuItem)" > {{ menuItem.label }} </li> </ul> <slot name="body"></slot> <slot name="footer"></slot> </div> </div> </template> <script> import { getUId } from "../../../utils/strTool"; export default { name: "JMouseMenu", props: { domId: { type: String, default: "", }, menu: { type: Array, default: () => { return []; }, }, }, data() { return { uid: "", }; }, created() { this.setUid(); }, mounted() { this.init(); }, methods: { setUid() { this.uid = "j-mouse-menu-" + getUId(); }, init() { // 自定義鼠標(biāo)右鍵菜單欄 const dom = document.getElementById(this.domId); if (!dom) return; const menu = document.getElementById(this.uid); const that = this; dom.oncontextmenu = function (e) { that.hideAllMenu(that.uid); // 自定義body元素的鼠標(biāo)事件處理函數(shù) e = e || window.event; e.preventDefault(); let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 獲取垂直滾動條位置 let scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; // 獲取水平滾動條位置 menu.style.display = "block"; menu.style.left = e.clientX + scrollLeft + "px"; menu.style.top = e.clientY + scrollTop + "px"; }; // 鼠標(biāo)點擊其他位置時隱藏菜單 document.onclick = function () { that.hideAllMenu(); }; }, hideAllMenu(id) { const jMenu = document.getElementsByClassName("j-mouse-menu"); for (let i = 0; i < jMenu.length; i++) { if (jMenu[i].id != id) jMenu[i].style.display = "none"; } }, menuClick(item) { if (item.click) { item.click(item); return; } this.$emit("menuClick", item); }, }, }; </script> <style lang="less" scoped> .j-mouse-menu { display: none; position: absolute; min-width: 8em; max-width: 15em; border: 1px solid #ccc; background: #eee; ul { margin: 5px 0; padding: 0; } li { height: 30px; line-height: 30px; color: #21232e; font-size: 12px; text-align: center; cursor: default; padding: 0; margin: 0; list-style-type: none; border-bottom: 1px dashed #cecece; &:hover { background-color: #cccccc; } } } </style>
(5)組件使用
<j-mouse-menu :domId="'j-mouse-menu-view-content1'" :menu="myMenu" @menuClick="menuClick" > <template v-slot:header> <div class="menu-slot-header">??JYeontu</div> </template> <template v-slot:footer> <div class="menu-slot"> ???? </div> </template> </j-mouse-menu>
通過插槽自定義右鍵菜單的頭部和底部內(nèi)容,菜單列表通過menu
參數(shù)傳入子組件,并綁定菜單點擊事件menuClick
。
data(){ return { myMenu: [ { id: "1", label: "菜單1" }, { id: "2", label: "菜單2", click: this.test }, { id: "3", label: "菜單3" }, { id: "4", label: "菜單4" }, { id: "5", label: "菜單5" } ] } }, methods:{ menuClick(menuItem) { alert("點擊了:" + menuItem.label); }, test(menuItem) { alert("test-" + menuItem.id); }, alert(label) { alert("點擊了:" + label); } }
組件庫
組件文檔
目前該組件也已經(jīng)收錄到我的組件庫,組件文檔地址如下:http://jyeontu.xyz/jvuewheel/#/JMouseMenu
組件內(nèi)容
組件庫中還有許多好玩有趣的組件,如:
- 懸浮按鈕
- 評論組件
- 詞云
- 瀑布流照片容器
- 視頻動態(tài)封面
- 3D輪播圖
- web桌寵
- 貢獻(xiàn)度面板
- 拖拽上傳
- 自動補全輸入框
- 圖片滑塊驗證
等等……
組件庫源碼
組件庫已開源到gitee,有興趣的也可以到這里看看:https://gitee.com/zheng_yongtao/jyeontu-component-warehouse
以上就是使用Vue封裝一個自定義的右鍵菜單組件的詳細(xì)內(nèi)容,更多關(guān)于Vue自定義右鍵菜單組件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue?serve及其與vue-cli-service?serve之間的關(guān)系解讀
這篇文章主要介紹了vue?serve及其與vue-cli-service?serve之間的關(guān)系,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10vue之組件內(nèi)監(jiān)控$store中定義變量的變化詳解
今天小編就為大家分享一篇vue之組件內(nèi)監(jiān)控$store中定義變量的變化詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11el-radio-group中的area-hidden報錯的問題解決
本文主要介紹了el-radio-group中的area-hidden報錯的問題解決,下面就來介紹幾種解決方法,具有一定的參考價值,感興趣的可以了解一下2025-04-04vue中同時監(jiān)聽多個參數(shù)的實現(xiàn)
這篇文章主要介紹了vue中同時監(jiān)聽多個參數(shù)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04