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 相关文章推荐
快速解决vue2+vue-cli3项目ie兼容的问题
Nov 17 Vue.js
vue + el-form 实现的多层循环表单验证
Nov 25 Vue.js
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
vue 通过base64实现图片下载功能
Dec 19 Vue.js
Vue——解决报错 Computed property &quot;****&quot; was assigned to but it has no setter.
Dec 19 Vue.js
详解Vue的异步更新实现原理
Dec 22 Vue.js
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
Vue实现一种简单的无限循环滚动动画的示例
Jan 10 Vue.js
vue二选一tab栏切换新做法实现
Jan 19 Vue.js
vue中h5端打开app(判断是安卓还是苹果)
Feb 26 Vue.js
如何用vue实现网页截图你知道吗
Nov 17 Vue.js
vue实现简易音乐播放器
Aug 14 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
ThinkPHP表单自动验证实例
2014/10/13 PHP
CodeIgniter配置之database.php用法实例分析
2016/01/20 PHP
PHP执行shell脚本运行程序不产生core文件的方法
2016/12/28 PHP
javascript中的有名函数和无名函数
2007/10/17 Javascript
JS连连看源码完美注释版(推荐)
2013/12/09 Javascript
前台js对象在后台转化java对象的问题探讨
2013/12/20 Javascript
JavaScript异步编程Promise模式的6个特性
2014/04/03 Javascript
js鼠标点击图片切换效果实现代码
2015/11/19 Javascript
HTML5 Shiv完美解决IE(IE6/IE7/IE8)不兼容HTML5标签的方法
2015/11/25 Javascript
jQuery的事件预绑定
2016/12/05 Javascript
Vue-resource拦截器判断token失效跳转的实例
2017/10/27 Javascript
安装vue-cli的简易过程
2018/05/22 Javascript
Node.js连接Sql Server 2008及数据层封装详解
2018/08/27 Javascript
JavaScript 对引擎、运行时、调用堆栈的概述理解
2018/10/22 Javascript
使用vuex较为优雅的实现一个购物车功能的示例代码
2019/12/09 Javascript
Vue利用localStorage本地缓存使页面刷新验证码不清零功能的实现
2020/09/04 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
2020/12/03 Javascript
[36:29]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs TNC
2018/04/02 DOTA
python 装饰器功能以及函数参数使用介绍
2012/01/27 Python
python matplotlib 注释文本箭头简单代码示例
2018/01/08 Python
将pip源更换到国内镜像的详细步骤
2019/04/07 Python
Python使用统计函数绘制简单图形实例代码
2019/05/15 Python
tf.concat中axis的含义与使用详解
2020/02/07 Python
最新2019Pycharm安装教程 亲测
2020/02/28 Python
python爬虫开发之使用python爬虫库requests,urllib与今日头条搜索功能爬取搜索内容实例
2020/03/10 Python
详解Ubuntu环境下部署Django+uwsgi+nginx总结
2020/04/02 Python
Tensorflow之MNIST CNN实现并保存、加载模型
2020/06/17 Python
python2和python3哪个使用率高
2020/06/23 Python
Christys’ Hats官网:英国帽子制造商
2018/11/28 全球购物
美国Jeep配件购物网站:Morris 4×4 Center
2019/05/01 全球购物
罗马尼亚购物网站:Vivantis.ro
2019/07/20 全球购物
大学自主招生自荐信范文
2014/02/26 职场文书
租房协议书怎么写
2014/04/10 职场文书
冰峪沟导游词
2015/02/09 职场文书
2015年学校政教工作总结
2015/07/20 职场文书
Flask response响应的具体使用
2021/07/15 Python