Vue中 实现右键自定义菜单

简介: Vue中 实现右键自定义菜单

1. 原生方法

1.1 完整代码

<template>
  <div class="home">
    <!-- 在需要右键菜单的元素,绑定contextmenu事件 -->
    <div 
      class="test" v-for="item in menus" :key="item" 
      @contextmenu.prevent="openMenu($event,item)">{{item}}</div>
    <!-- 右键菜单部分 -->
    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
      <li @click="handleDelete">删除</li>
      <li @click="handleDownloadFile">下载</li>
      <li @click="handlePreviewFile">预览</li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      menus:[1,2,3], // 模拟数据
      rightClickItem:'',
      visible: false, // 是否展示右键菜单
      top:0,
      left:0,
    };
  },
  methods: {
    // 打开右键菜单
    openMenu(e,item){
      this.visible = true;
      this.top = e.pageY;
      this.left = e.pageX;
      this.rightClickItem = item;
    },
    // 关闭右键菜单
    closeMenu(){
      this.visible = false;
    },
    handleDelete(){},
    handleDownloadFile(){},
    handlePreviewFile(){},
  },
  watch: {
    // 监听 visible,来触发关闭右键菜单,调用关闭菜单的方法
    visible(value) {
      if (value) {
        document.body.addEventListener('click', this.closeMenu)
      } else {
        document.body.removeEventListener('click', this.closeMenu)
      }
    }
  },
};
</script>
<style lang="stylus" scoped>
.home{
  display: flex;
  justify-content: space-around;
  width: 100%;
  height: 600px;
  .test{
    width: 80px;
    height: 60px;
    background-color pink;
    text-align:center;
    font-size:32px;  
    color: green;
  }
  .contextmenu {
    margin: 0;
    background: #fff;
    z-index: 3000;
    position: absolute;
    list-style-type: none;
    padding: 5px 0;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 400;
    color: #333;
    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
  }
  .contextmenu li {
    margin: 0;
    padding: 7px 16px;
    cursor: pointer;
  }
  .contextmenu li:hover {
    background: #eee;
  }
}
</style>

1.2 效果

2020062310470442.png

2. 使用插件 vue-context-menu

demo演示地址

GitHub地址

npm 地址

安装

npm install vue-contextmenu --save

引入

import VueContextMenu from 'vue-contextmenu'
Vue.use(VueContextMenu)

2.1 普通列表菜单

2.1.1 完整代码

<template>
  <div 
    id="app" @contextmenu="showMenu"
    style="width: 200px;height: 200px;margin-top: 20px;background: pink;">
    <vue-context-menu 
      :contextMenuData="contextMenuData" @deleteData="deleteData" @newAdd="newAdd">
    </vue-context-menu>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 菜单数据
      contextMenuData: {
        menuName: 'demo',
        // 菜单显示的位置
        axis: {
          x: null,
          y: null
        },
        // 菜单选项
        menulists: [
          {
            fnHandler: 'deleteData', // 绑定事件
            icoName: 'el-icon-delete', // 图标 (本文取自 element-ui)
            btnName: '保存' // 菜单名称
          },{
            fnHandler: 'newAdd',
            icoName: 'el-icon-plus',
            btnName: '新增'
          }
        ]
      }
    };
  },
  methods: {
    showMenu () {
      event.preventDefault()
      var x = event.clientX;
      var y = event.clientY;
      // 获取当前位置
      this.contextMenuData.axis = { x, y }
    },
    // 删除
    deleteData () {},
    // 新增
    newAdd () {}
  },
  watch: {},
};
</script>

2.1.2 效果

2020062310470442.png


2.2 树型菜单

2.2.1 完整代码

<template>
  <div style="position: fixed; left: 0px; top: 0">
    <div
      @contextmenu="showMenu(index)"
      style="width: 100px; height: 100px; margin-top: 20px; background: red"
      v-for="(n, index) in 2"
      :key="n"
    >
      <vue-context-menu
        :contextMenuData="contextMenuData"
        :transferIndex="transferIndex"
        @Handler1="Handler_A(index)"
        @Handler2="Handler_B(index)"
        @Handler3="Handler_C(index)"
      ></vue-context-menu>
    </div>
  </div>
</template>
<script>
export default {
  name: "app",
  data() {
    return {
      transferIndex: null,
      contextMenuData: {
        menuName: "demo",
        axis: {
          x: null,
          y: null,
        },
        menulists: [
          {
            btnName: "选项1",
            icoName: "el-icon-s-tools",
            children: [
              {
                icoName: "el-icon-download",
                btnName: "选项1-1",
                // 子菜单
                children: [
                  {
                    icoName: "el-icon-share",
                    btnName: "选项1-1-1",
                    children: [
                      {
                        icoName: "el-icon-switch-button",
                        fnHandler: "Handler1",
                        btnName: "选项1-1-1",
                      },
                    ],
                  },
                ],
              },
            ],
          },
          {
            btnName: "选项2",
            children: [
              {
                fnHandler: "Handler2",
                btnName: "选项2-1",
              },
            ],
          },
          {
            btnName: "选项3",
            fnHandler: "Handler3",
          },
          {
            btnName: "选项4",
            disabled: true,
          },
        ],
      },
    };
  },
  methods: {
    showMenu(index) {
      this.transferIndex = index; // 将索引转换到子组件
      event.preventDefault();
      var x = event.clientX;
      var y = event.clientY;
      this.contextMenuData.axis = { x,y };
    },
    Handler_A(index) {
      console.log(index, "选项 1-1-1 绑定事件执行");
    },
    Handler_B(index) {
      console.log(index, "选项 2-1 绑定事件执行");
    },
    Handler_C(index) {
      console.log(index, "选项 3 绑定事件执行");
    },
  },
};
</script>
<style>
* {
  margin: 0;
  padding: 0;
}
</style>

2.2.2 效果

2020062310470442.png

参考文章


相关文章
|
6天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
6天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
6天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
|
12天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
12天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
12天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
12天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
11天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
13天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
11天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
下一篇
无影云桌面