取消原生右鍵事件 在 main.ts 函數中取消瀏覽器預設右鍵菜單: window.oncontextmenu = () => { return false; }; 組件模板 做一個不同區域右鍵點擊之後不同菜單項的組件,創建組件模板: <!-- ContextMenu --> <div ref="m ...
取消原生右鍵事件
在 main.ts 函數中取消瀏覽器預設右鍵菜單:
window.oncontextmenu = () => {
return false;
};
組件模板
做一個不同區域右鍵點擊之後不同菜單項的組件,創建組件模板:
<!-- ContextMenu -->
<div ref="menu" class="l-menu">
<slot />
<Teleport to="#l-menu-container">
<div
ref="panel"
:id="'l-menu__panel__' + milliseconds"
:style="{ left: x + 'px', top: y + 'px' }">
<div ref="head" class="l-menu__head">
<div class="l-menu__title">
<slot name="title" />
</div>
<div @click="panel.style.display = 'none'">
<i-ep-close />
</div>
</div>
<div class="l-menu__main">
<slot name="content" />
</div>
</div>
</Teleport>
</div>
模板中使用了 Teleport
,需要把這一塊傳遞到頁面中 l-menu-container
元素中去,這個元素在 body 下,意思是我的右鍵菜單組件呼出的面板不受父組件的樣式影響,包括移動的範圍限制、背景顏色等,這些繼承父元素樣式都需要避免。
組件 setup
需要獲取組件模板的一些引用:
// ContextMenu setup
const menu = ref<HTMLElement>();
const head = ref<HTMLElement>();
const panel = ref<HTMLElement>();
const milliseconds = new Date().getMilliseconds();
const { x, y } = useDraggable(head);
onMounted(() => {
menu.value.onmouseup = e => {
if (e.button == 2) {
const container = document.querySelector("#l-menu-container");
const menuId = container.getAttribute("menu-id");
menuId && (document.getElementById(`l-menu__panel__${menuId}`).style.display = "none");
container.setAttribute("menu-id", `${milliseconds}`);
panel.value.style.left = `${e.clientX}px`;
panel.value.style.top = `${e.clientY}px`;
panel.value.style.display = "block";
}
};
});
滑鼠按下放開事件,判斷滑鼠是左鍵還是右鍵,button 為 2 代表右鍵,右鍵點擊之後需要移除上一個開啟的面板,在 body 下的 #l-menu-container
元素上添加一個記錄上一次面板的 id。
實現右鍵出來之後的菜單面板自由地在視窗中移動,直接藉助 VueUse useDraggable
函數:
const { x, y } = useDraggable(head);
得到滑鼠移動的 x 和 y 值,通過綁定 style 對 left 和 top 進行設置,就可以實現自由移動。
使用組件
該組件有三個插槽,一個預設插槽,兩個具名插槽。具名 content 插槽是菜單內容,預設插槽是能呼出右鍵菜單面板的區域,哪個區域能呼出就在外面套一層 ContextMenu 組件:
<ContextMenu>
<div class="item">
hello
</div>
<template #title>樣式設置</template>
<template #content>
<BoxSetting />
</template>
</ContextMenu>