vue實(shí)現(xiàn)自定義全局右鍵菜單
前段時間公司在做一個webIDE項(xiàng)目,其中有對文件樹的各種操作,主要通過右鍵菜單實(shí)現(xiàn),今天就來記錄一下怎么在vue項(xiàng)目中實(shí)現(xiàn)全局的自定義右鍵菜單。效果如圖所示:
注意:
需要在項(xiàng)目中找到頁面整體布局的組件,比如項(xiàng)目使用Home.vue作為整個項(xiàng)目的公共布局,將根元素定位設(shè)置成relative,使右鍵菜單相對于其進(jìn)行定位。
本文的右鍵菜單主要使用vuex實(shí)現(xiàn)
一、vuex中定義全局狀態(tài)用于管理右鍵菜單
export default { ? ? /** ? ? ?* menuContent格式: ? ? ?* [ ? ? ?* ? ? ?{ ? ? ?* ? ? ? ? ?name: '新建文件', ? // 操作名 ? ? ?* ? ? ? ? ?method: 'createDirectory', ?// 需要執(zhí)行的對應(yīng)組件中的方法 ? ? ?* ?? ??? ??? ?disabled: true?? ??? ?// 是否禁用,可以根據(jù)頁面具體邏輯進(jìn)行調(diào)整 ? ? ?* ? ? ?} ? ? ?* ] ?? ? *? ?? ? *? ?? ? * 整體右鍵菜單采用絕對定位,所以clientX、clientY代表是left和top定位 ? ? ?*/ ? ? state: { ? ? ? ? menuContent: [], ? ?// 右鍵菜單內(nèi)容 ? ? ? ? clientX: '', ? ?// left ? ? ? ? clientY: '', ? ?// top ? ? ? ? displayContextMenu: false ? // 是否展示右鍵菜單 ? ? }, ? ? mutations: { ? ? ? ? SET_CONTEXT_MENU: (state, payload) => { ? ? ? ? ? ? state.menuContent = payload.menuContent; ? ? ? ? ? ? state.clientX = payload.clientX; ? ? ? ? ? ? state.clientY = payload.clientY; ? ? ? ? ? ? state.displayContextMenu = payload.displayContextMenu; ? ? ? ? }, ? ? } }
二、定義公共組件ContextMenu.vue
<template> ? ? <div class="context-menu" v-show="contextMenu.displayContextMenu"? ? ? ? ? :style="{'left': contextMenu.clientX + 'px', 'top': contextMenu.clientY + 'px'}"> ? ? ? ? <ul> ? ? ? ? ? ? <li v-for="(item, i) in contextMenu.menuContent" :key="i" :class="item.disabled ? 'disabled' : ''"? ? ? ? ? ? ? ? ? @click="emitEvent(item.method)"> ? ? ? ? ? ? ? ? {{item.name}} ? ? ? ? ? ? </li> ? ? ? ? </ul> ? ? </div> </template> <script> import { mapState } from 'vuex'; import bus from '@/views/common/bus'; export default { ? ? name: 'ContextMenu', ? ? data(){ ? ? ? ? return { ? ? ? ? } ? ? }, ? ? computed: { ? ? ? ? ...mapState(['contextMenu']) ? ? }, ? ? methods: { ? ? ? ? emitEvent(type){ ? ? ? ? ? ? bus.$emit('operateDirectory', type) ? ? ? ? } ? ? } } </script> <style lang="scss" scoped> ? ? .context-menu { ? ? ? ? position: absolute; ? ? ? ? background: #FFF; ? ? ? ? color: #34495E; ? ? ? ? min-width: 100px; ? ? ? ? box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2); ? ? ? ? border-radius: 2px; ? ? ? ? cursor: pointer; ? ? ? ? z-index: 1002; ? ? ? ? &>ul { ? ? ? ? ? ? text-align: left; ? ? ? ? ? ? padding: 5px 10px; ? ? ? ? ? ? &>li { ? ? ? ? ? ? ? ? padding: 3px 4px; ? ? ? ? ? ? ? ? font-size: 12px; ? ? ? ? ? ? ? ? list-style: none; ? ? ? ? ? ? ? ? height: 24px; ? ? ? ? ? ? ? ? line-height: 24px; ? ? ? ? ? ? ? ? &:hover { ? ? ? ? ? ? ? ? ? ? background: #EDF6FF; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? .disabled { ? ? ? ? ? ? ? ? color: #888585; ? ? ? ? ? ? ? ? pointer-events: none; ? ? ? ? ? ? } ? ? ? ? } ? ? } </style>
三、在組件中使用
import { mapState } from 'vuex'; // ... computed: { ?? ?...mapState(['contextMenu']) }, created(){ ?? ?bus.$on('operateDirectory', (param) => { ?? ?// 點(diǎn)擊右鍵菜單時,應(yīng)觸發(fā)組件內(nèi)的同名方法,首先應(yīng)判斷該方法是否在本組件內(nèi)存在,存在則調(diào)用 ?? ??? ?if(this[param]){ ?? ??? ??? ?this[param](); ?? ??? ?} ?? ?}); }, // ... methods: { ?? ?showContextMenu(event, data) { ? ? ? ? event.preventDefault();?? ??? ?// 阻止瀏覽器的默認(rèn)事件 ? ? ? ? const menuContent = { ? ? ? ? ? ? menuContent: [ ? ? ? ? ? ? { ? ? ? ? ? ? ? ? icon: "el-icon-upload2", ? ? ? ? ? ? ? ? name: "運(yùn)行", ? ? ? ? ? ? ? ? method: "run", ? ? ? ? ? ? }, ? ? ? ? ? ? { ? ? ? ? ? ? ? ? icon: "el-icon-refresh", ? ? ? ? ? ? ? ? name: "編輯", ? ? ? ? ? ? ? ? method: "editConfig", ? ? ? ? ? ? }, ? ? ? ? ? ? { ? ? ? ? ? ? ? ? icon: "el-icon-refresh", ? ? ? ? ? ? ? ? name: "添加", ? ? ? ? ? ? ? ? method: "addCommond", ? ? ? ? ? ? }, ? ? ? ? ? ? { ? ? ? ? ? ? ? ? icon: "el-icon-refresh", ? ? ? ? ? ? ? ? name: "刪除", ? ? ? ? ? ? ? ? method: "deleteConfig", ? ? ? ? ? ? }, ? ? ? ? ? ? ], ? ? ? ? ? ? clientX: event.clientX, ? ? ? ? ? ? clientY: event.clientY, ? ? ? ? ? ? displayContextMenu: true, ? ? ? ? }; ? ? ? ? this.$store.commit("SET_CONTEXT_MENU", menuContent); ? ? ? ? // 再次點(diǎn)擊頁面,右鍵菜單消失 ? ? ? ? document.onclick = (event) => { ? ? ? ? ? ? this.$store.commit("SET_CONTEXT_MENU", { ? ? ? ? ? ? ? ? displayContextMenu: false, ? ? ? ? ? ? }); ? ? ? ? }; ? ? }, ? ? run(){ ?? ??? ?// ... ?? ?}, ?? ?editConfig(){ ?? ??? ?// ... ?? ?}, ?? ?addCommond(){ ?? ??? ?// ... ?? ?}, ?? ?deleteConfig(){ ?? ??? ?// ... ?? ?} }
總結(jié)
這種可以實(shí)現(xiàn)全局右鍵菜單,并且支持自定義右鍵內(nèi)容,但是vue3.0對event bus的取消會導(dǎo)致不可用。
目前有一種優(yōu)化方法:項(xiàng)目中對應(yīng)會使用組件庫,例如element ui,在定義contextMenu.vue的時候,使用dialog,將內(nèi)容定義在Popover 彈出框中,當(dāng)組件使用右鍵菜單時,使用子組件的方式使用ContextMenu.vue,點(diǎn)擊右鍵菜單內(nèi)容時就不需要使用emit觸發(fā)了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vuex實(shí)現(xiàn)數(shù)據(jù)增加和刪除功能
今天小編就為大家分享一篇Vuex實(shí)現(xiàn)數(shù)據(jù)增加和刪除功能,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11Vue項(xiàng)目使用localStorage+Vuex保存用戶登錄信息
這篇文章主要為大家詳細(xì)介紹了Vue項(xiàng)目使用localStorage+Vuex保存用戶登錄信息,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-05-05Vue3組合式API之getCurrentInstance詳解
我們可以通過?getCurrentInstance這個函數(shù)來返回當(dāng)前組件的實(shí)例對象,也就是當(dāng)前vue這個實(shí)例對象,下面這篇文章主要給大家介紹了關(guān)于Vue3組合式API之getCurrentInstance的相關(guān)資料,需要的朋友可以參考下2022-09-09vue中axios處理http發(fā)送請求的示例(Post和get)
本篇文章主要介紹了vue中axios處理http請求的示例(Post和get),這里整理了詳細(xì)的代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10