Implement right-click custom menu in Vue

1. Native methods

1.1 Complete code

<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 Effect
Insert picture description here

2. Use the plugin vue-context-menu

Demo demo address
GitHub address
npm address

installation

npm install vue-contextmenu --save

Introduce

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

2.1 Normal list menu
2.1.1 Complete code

<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 Effect
Insert picture description here
2.2 Tree menu
2.2.1 Complete code

<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 Effect
Insert picture description here

Reference article

Guess you like

Origin blog.csdn.net/ZYS10000/article/details/109707751