vue自定义右键菜单之全局实现


Posted in Vue.js onApril 09, 2022

前段时间公司在做一个webIDE项目,其中有对文件树的各种操作,主要通过右键菜单实现,今天就来记录一下怎么在vue项目中实现全局的自定义右键菜单。效果如图所示:

vue自定义右键菜单之全局实现

注意:

需要在项目中找到页面整体布局的组件,比如项目使用Home.vue作为整个项目的公共布局,将根元素定位设置成relative,使右键菜单相对于其进行定位。

本文的右键菜单主要使用vuex实现

一、vuex中定义全局状态用于管理右键菜单

export default {
    /**
     * menuContent格式:
     * [
     *      {
     *          name: '新建文件',   // 操作名
     *          method: 'createDirectory',  // 需要执行的对应组件中的方法
     *             disabled: true        // 是否禁用,可以根据页面具体逻辑进行调整
     *      }
     * ]
     * 
     * 
     * 整体右键菜单采用绝对定位,所以clientX、clientY代表是left和top定位
     */
    state: {
        menuContent: [],    // 右键菜单内容
        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) => {
    // 点击右键菜单时,应触发组件内的同名方法,首先应判断该方法是否在本组件内存在,存在则调用
        if(this[param]){
            this[param]();
        }
    });
},
// ...

methods: {
    showContextMenu(event, data) {
        event.preventDefault();        // 阻止浏览器的默认事件
        const menuContent = {
            menuContent: [
            {
                icon: "el-icon-upload2",
                name: "运行",
                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);
        // 再次点击页面,右键菜单消失
        document.onclick = (event) => {
            this.$store.commit("SET_CONTEXT_MENU", {
                displayContextMenu: false,
            });
        };
    },
    run(){
        // ...
    },
    editConfig(){
        // ...
    },
    addCommond(){
        // ...
    },
    deleteConfig(){
        // ...
    }
}

总结

这种可以实现全局右键菜单,并且支持自定义右键内容,但是vue3.0对event bus的取消会导致不可用。

目前有一种优化方法:项目中对应会使用组件库,例如element ui,在定义contextMenu.vue的时候,使用dialog,将内容定义在Popover 弹出框中,当组件使用右键菜单时,使用子组件的方式使用ContextMenu.vue,点击右键菜单内容时就不需要使用emit触发了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Vue.js 相关文章推荐
实用的 vue tags 创建缓存导航的过程实现
Dec 03 Vue.js
vue中activated的用法
Jan 03 Vue.js
jenkins自动构建发布vue项目的方法步骤
Jan 04 Vue.js
Vue SPA 首屏优化方案
Feb 26 Vue.js
vite2.0+vue3移动端项目实战详解
Mar 03 Vue.js
vue3.0中使用element的完整步骤
Mar 04 Vue.js
vue中data改变后让视图同步更新的方法
Mar 29 Vue.js
Vue实现tab导航栏并支持左右滑动功能
Jun 28 Vue.js
SSM VUE Axios详解
Oct 05 Vue.js
Vue.Draggable实现交换位置
Apr 07 Vue.js
vue实现列表垂直无缝滚动
Apr 08 Vue.js
vue动态绑定style样式
Apr 20 Vue.js
vue判断按钮是否可以点击
Apr 09 #Vue.js
VUE之图片Base64编码使用ElementUI组件上传
Apr 09 #Vue.js
vue如何实现关闭对话框后刷新列表
Apr 08 #Vue.js
vue实现列表垂直无缝滚动
Apr 08 #Vue.js
vue3引入highlight.js进行代码高亮的方法实例
vue中的可拖拽宽度div的实现示例
vue 实现弹窗关闭后刷新效果
Apr 08 #Vue.js
You might like
php中神奇的fastcgi_finish_request
2011/05/02 PHP
php漏洞之跨网站请求伪造与防止伪造方法
2013/08/15 PHP
使用ThinkPHP生成缩略图及显示
2017/04/27 PHP
PHP不使用内置函数实现字符串转整型的方法示例
2017/07/03 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
2018/07/20 PHP
PDO::setAttribute讲解
2019/01/29 PHP
Prototype 学习 工具函数学习($A方法)
2009/07/12 Javascript
jQueryPad 实用的jQuery测试工具(支持IE,chrome,FF)
2010/05/22 Javascript
AngularJs根据访问的页面动态加载Controller的解决方案
2015/02/04 Javascript
Javascript显示和隐藏ul列表的方法
2015/07/15 Javascript
javascript比较两个日期相差天数的方法
2015/07/23 Javascript
vue,angular,avalon这三种MVVM框架优缺点
2016/04/27 Javascript
Javascript获取随机数的实现方法
2016/06/22 Javascript
vue-router路由简单案例介绍
2017/02/21 Javascript
echart简介_动力节点Java学院整理
2017/08/11 Javascript
Vue实现点击后文字变色切换方法
2018/02/11 Javascript
详解Vue 多级组件透传新方法provide/inject
2018/05/09 Javascript
微信小程序实现多选删除列表数据功能示例
2019/01/15 Javascript
Nest.js环境变量配置与序列化详解
2021/02/21 Javascript
[02:29]DOTA2英雄基础教程 陈
2013/12/17 DOTA
python 出现SyntaxError: non-keyword arg after keyword arg错误解决办法
2017/02/14 Python
对pycharm 修改程序运行所需内存详解
2018/12/03 Python
Python在终端通过pip安装好包以后在Pycharm中依然无法使用的问题(三种解决方案)
2020/03/10 Python
澳大利亚音乐商店:Bava’s Music City
2019/05/05 全球购物
给水排水工程专业毕业生推荐信
2013/10/28 职场文书
领导接待方案
2014/03/13 职场文书
手术室护士长竞聘书
2014/03/31 职场文书
小学班长竞选演讲稿
2014/04/24 职场文书
国庆节演讲稿范文2014
2014/09/19 职场文书
单位委托书格式范本
2014/09/29 职场文书
2014年保险公司工作总结
2014/11/22 职场文书
护士个人年终总结
2015/02/13 职场文书
2015年学校精神文明工作总结
2015/05/27 职场文书
学术研讨会主持词
2015/07/04 职场文书
2016年保险公众宣传日活动总结
2016/04/05 职场文书
js作用域及作用域链工作引擎
2022/07/07 Javascript