使用Vue封裝一個(gè)自定義的右鍵菜單組件
說在前面
網(wǎng)頁的功能和用途可能各不相同,在傳統(tǒng)右鍵菜單欄中無法滿足每個(gè)用戶的個(gè)性化需求。通過自定義右鍵菜單欄,用戶可以根據(jù)自己的需求添加、調(diào)整和刪除菜單選項(xiàng),以實(shí)現(xiàn)個(gè)性化定制。通過自定義右鍵菜單欄,可以為用戶提供快速訪問常用功能和操作的便捷方式,從而提高用戶體驗(yàn)。
效果展示


實(shí)現(xiàn)原理
1、oncontextmenu事件了解一下
oncontextmenu 事件在元素中用戶右擊鼠標(biāo)時(shí)觸發(fā)并打開上下文菜單。
oncontextmenu是一個(gè)DOM事件,它在用戶右鍵點(diǎn)擊時(shí)觸發(fā)??梢酝ㄟ^在HTML元素上添加oncontextmenu屬性來指定右鍵菜單的處理函數(shù)。
例如,在一個(gè)按鈕元素上添加oncontextmenu屬性:
<button oncontextmenu="showContextMenu(event)">右鍵點(diǎn)擊我</button>
在這個(gè)示例中,當(dāng)用戶右鍵點(diǎn)擊按鈕時(shí),會調(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ǎn)擊事件時(shí),首先調(diào)用hideAllMenu方法隱藏所有的右鍵菜單,然后通過event.preventDefault方法禁止默認(rèn)行為,防止瀏覽器彈出默認(rèn)的右鍵菜單。接下來,計(jì)算出鼠標(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)用戶在其他位置點(diǎn)擊鼠標(biāo)時(shí),調(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、封裝成一個(gè)組件
(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屬性,該屬性值由組件實(shí)例的uid屬性提供。這樣可以確保每個(gè)組件實(shí)例都有唯一的id。
然后,給組件添加了j-mouse-menu類,用于設(shè)置組件的樣式。
在組件的內(nèi)容區(qū)域中,使用了Vue的插槽機(jī)制。
<slot name="header"></slot>定義了一個(gè)名為"header"的插槽,用于放置菜單欄的頭部內(nèi)容。<ul>標(biāo)簽下使用了v-for指令遍歷menu數(shù)組,生成菜單項(xiàng)。- 菜單項(xiàng)使用
<li>標(biāo)簽表示,并通過:key綁定了唯一的menuItem.id作為key值。 - 通過
@click綁定了menuClick方法,該方法會在點(diǎn)擊菜單項(xiàng)時(shí)被調(diào)用。 - 菜單項(xiàng)的顯示文本使用插值語法
{{ menuItem.label }}來動態(tài)顯示。
接下來,又定義了兩個(gè)插槽:
<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表示右鍵菜單的選項(xiàng)列表,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ǎn)擊回調(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屬性,即沒有自定義的點(diǎn)擊處理函數(shù),那么就通過this.$emit("menuClick", item)語法觸發(fā)一個(gè)名為"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)點(diǎn)擊其他位置時(shí)隱藏菜單
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ù)傳入子組件,并綁定菜單點(diǎn)擊事件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("點(diǎn)擊了:" + menuItem.label);
},
test(menuItem) {
alert("test-" + menuItem.id);
},
alert(label) {
alert("點(diǎn)擊了:" + label);
}
}
組件庫
組件文檔
目前該組件也已經(jīng)收錄到我的組件庫,組件文檔地址如下:http://jyeontu.xyz/jvuewheel/#/JMouseMenu
組件內(nèi)容
組件庫中還有許多好玩有趣的組件,如:
- 懸浮按鈕
- 評論組件
- 詞云
- 瀑布流照片容器
- 視頻動態(tài)封面
- 3D輪播圖
- web桌寵
- 貢獻(xiàn)度面板
- 拖拽上傳
- 自動補(bǔ)全輸入框
- 圖片滑塊驗(yàn)證
等等……
組件庫源碼
組件庫已開源到gitee,有興趣的也可以到這里看看:https://gitee.com/zheng_yongtao/jyeontu-component-warehouse
以上就是使用Vue封裝一個(gè)自定義的右鍵菜單組件的詳細(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)系,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
vue之組件內(nèi)監(jiān)控$store中定義變量的變化詳解
今天小編就為大家分享一篇vue之組件內(nèi)監(jiān)控$store中定義變量的變化詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
el-radio-group中的area-hidden報(bào)錯(cuò)的問題解決
本文主要介紹了el-radio-group中的area-hidden報(bào)錯(cuò)的問題解決,下面就來介紹幾種解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下2025-04-04
vue中同時(shí)監(jiān)聽多個(gè)參數(shù)的實(shí)現(xiàn)
這篇文章主要介紹了vue中同時(shí)監(jiān)聽多個(gè)參數(shù)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04

