Vue3封裝實現(xiàn)右鍵菜單組件
實現(xiàn)思路
在 Vue 中封裝右鍵菜單組件時,可以通過 addEventListener 監(jiān)聽 contextmenu 事件,也可以直接在標簽上綁定 @contextmenu事件。由于我們在 Vue 中封裝組件,應(yīng)當充分利用框架的優(yōu)勢,使用 @contextmenu 語法來讓代碼更簡潔和易于維護。
封裝組件
由于不同區(qū)域需要顯示不同的菜單項,因此該組件的菜單項由外部傳入。
defineExpose將變量、方法暴露出去,使得父組件能夠訪問這些暴露的內(nèi)容
menu.vue
<template> <div class="menu" v-if="show" ref="menuRef"> <div class="menu-item" v-for="(item, index) in operation" :key="index" @click="handleClick(item.name)" > { { item.name }} </div> </div> </template> <script lang="ts" setup> //友情提示:如果使用的不是naive-ui可以直接將有關(guān)naive-ui的代碼注釋掉 import { useMessage } from 'naive-ui' import { nextTick, ref } from 'vue' //使用naive-ui的消息提示框,要在根組件使用 <n-message-provider></>n-message-provider> let message = useMessage() //點擊菜單項 const handleClick = (name) => { message.info(name) show.value = false } // 接收父組件傳入的菜單項 defineProps({ operation: { type: Array, default: () => [], }, }) //用來顯示、隱藏菜單 const show = ref(false) let menuRef = ref() //獲取并設(shè)置菜單的位置 const setPosition = (x, y) => { nextTick(() => { let dom = menuRef.value dom.style.left = x + 'px' dom.style.top = y + 'px' dom.style.height = 'fit-content' let height = dom.style.height dom.style.height = height }) } //暴露數(shù)據(jù) defineExpose({ show, setPosition, }) </script> <style lang="scss" scoped> .menu { width: 100px; padding-top: 10px; padding-bottom: 10px; border-radius: 10px; background: #ffffff; height: 0px; position: absolute; z-index: 1000; .menu-item { font-size: 16px; width: 100%; text-align: center; padding-top: 4px; padding-bottom: 4px; cursor: pointer; transition: 0.5s; } .menu-item:hover { background: #e2e2e2; transition: 0.5s; } } </style>
使用組件
在父組件使用組件 在頁面中,我們通常會劃分多個區(qū)域,右鍵點擊不同的區(qū)域時展示不同的菜單。在這種情況下,需要在事件處理函數(shù)中阻止瀏覽器的默認右鍵菜單彈出。此外,如果區(qū)域內(nèi)嵌套了其他區(qū)域,還需要阻止事件冒泡,確保事件只在當前區(qū)域內(nèi)處理,從而避免影響到其他區(qū)域的右鍵菜單。
index.vue
<template> <div class="contextMenu" @click="displayNoneMenu()"> <div class="box-1 box" @contextmenu="handleContextMenu($event, 'operationRef')" > <div class="text">操作區(qū)</div> <Menu ref="operationRef" :operation="operation"></Menu> <div class="box-1-1" @contextmenu.stop="handleContextMenu($event, 'operation2Ref')" > <div class="text">操作分區(qū)</div> <Menu ref="operation2Ref" :operation="operation2"></Menu> </div> </div> <div class="box-2 box" @contextmenu="handleContextMenu($event, 'settingRef')" > <div class="text">設(shè)置區(qū)</div> <Menu ref="settingRef" :operation="setting"></Menu> </div> <div class="box-3 box" @contextmenu="handleContextMenu($event, 'infoRef')"> <div class="text">信息區(qū)</div> <Menu ref="infoRef" :operation="info"></Menu> </div> <div class="box-4 box" @contextmenu="handleContextMenu($event, 'toolRef')"> <div class="text">工具區(qū)</div> <Menu ref="toolRef" :operation="tool"></Menu> </div> </div> </template> <script lang="ts" setup> import Menu from './menu.vue' import { ref } from 'vue' //不同的菜單 let operation = [ { name: '添加', }, { name: '刪除', }, { name: '編輯', }, ] let operation2 = [ { name: '查看詳情', }, { name: '查看用戶', }, ] let setting = [ { name: '修改屬性', }, { name: '更新', }, ] let info = [ { name: '查看日志', }, { name: '顯示數(shù)據(jù)', }, ] let tool = [ { name: '復(fù)制', }, { name: '粘貼', }, { name: '刪除', }, ] // 給子組件綁定ref 獲取組件實例 let operationRef = ref() let operation2Ref = ref() let settingRef = ref() let infoRef = ref() let toolRef = ref() // 緩存當前顯示的菜單 let currentMenuRef = ref() //點擊任何區(qū)域,隱藏菜單 const displayNoneMenu = () => { if (currentMenuRef.value) { currentMenuRef.value.show = false } } //右鍵事件 const handleContextMenu = (e, ref_) => { //阻止瀏覽器默認事件 e.preventDefault() if (currentMenuRef.value) { //在顯示下次菜單前,先隱藏上一次的菜單。 currentMenuRef.value.show = false } let menuRef = null switch (ref_) { case 'operationRef': menuRef = operationRef.value break case 'operation2Ref': menuRef = operation2Ref.value break case 'settingRef': menuRef = settingRef.value break case 'infoRef': menuRef = infoRef.value break case 'toolRef': menuRef = toolRef.value break } // 通過獲取到的組件實例,設(shè)置菜單的顯示和位置 menuRef.show = true menuRef.setPosition(e.offsetX, e.offsetY) currentMenuRef.value = menuRef } </script> <style lang="scss" scoped> .contextMenu { height: 100%; width: 100%; background: palegreen; border-radius: 10px; display: flex; flex-flow: wrap; .box { position: relative; } .box-1 { width: 40%; height: 40%; background: #25a4bb; .box-1-1 { width: 50%; height: 50%; background: coral; } } .box-2 { width: 60%; height: 40%; background: #cacaca; } .box-3 { width: 60%; height: 60%; background: palevioletred; } .box-4 { width: 40%; height: 60%; background: paleturquoise; } .text { font-weight: 600; font-size: 20px; color: #333333; text-align: center; font-family: 'Avenir', Helvetica, Arial, sans-serif; margin-top: 10px; } } </style>
效果
到此這篇關(guān)于Vue3封裝實現(xiàn)右鍵菜單組件的文章就介紹到這了,更多相關(guān)Vue3右鍵菜單組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何修改element-ui中tree組件的icon圖標(小白都會的前端技能)
這篇文章主要給大家介紹了關(guān)于如何修改element-ui中tree組件的icon圖標的相關(guān)資料,本文介紹的是小白都會的前端技能,文中通過代碼以及圖文介紹的非常詳細,需要的朋友可以參考下2024-01-01vue3+ts如何通過lodash實現(xiàn)防抖節(jié)流詳解
loadsh是一個工具庫,我們通常使用loadsh的debounce函數(shù)處理防抖,下面這篇文章主要給大家介紹了關(guān)于vue3+ts如何通過lodash實現(xiàn)防抖節(jié)流的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-08-08