您的位置:

Vue实现自定义右键菜单

一、Vue鼠标右键自定义菜单

在 Vue 中,我们可以使用 `v-contextmenu` 指令来绑定右键菜单事件。

这个指令接受一个方法名,这个方法会在右键菜单被触发时被调用。

先来看一个简单的例子,在下面的代码中,我们定义了一个右键菜单,并在 `showMenu` 方法中控制菜单的显示和隐藏。

  
    
   

    <script>
    export default {
      data() {
        return {
          show: false
        }
      },
      methods: {
        showMenu(e) {
          e.preventDefault();
          this.show = true;

          document.addEventListener("click", () => {
            this.show = false;
          }, { once: true });
        }
      }
    }
    </script>
  

二、Vue定义自定义鼠标右键

Vue 自带的指令只能帮我们绑定右键菜单事件,但是这些事件缺乏我们自定义菜单样式和内容的能力。

我们可以使用 `window.oncontextmenu` 监听右键菜单事件,并自定义菜单的样式和内容。

下面是一个自定义右键菜单的例子,我们可以通过 `v-html` 将菜单项渲染到菜单中。

  
    
   

    <script>
    export default {
      data() {
        return {
          left: 0,
          top: 0,
          menu: ""
        }
      },
      methods: {
        showMenu(e) {
          e.preventDefault();

          // 自定义菜单内容
          this.menu = `
            <li>菜单项1</li>
            <li>菜单项2</li>
            <li>菜单项3</li>
          `;

          // 自定义菜单样式
          this.left = e.clientX;
          this.top = e.clientY;

          // 在下一帧中关闭菜单
          this.$nextTick(() => {
            document.addEventListener("click", () => {
              this.menu = "";
            }, { once: true });
          });
        }
      }
    }
    </script>

    
  

三、Vue实现多级右键菜单

有时候我们需要实现一个多级的右键菜单,下面是一个简单的例子。

首先,我们需要定义一个菜单项组件,并使用 `v-for` 渲染出菜单项列表。

当鼠标进入菜单项时,我们使用 `setTimeout` 延迟 300 毫秒显示下一级菜单,当鼠标移出菜单项时,隐藏下一级菜单。

  
    
   

    <script>
    import MenuItem from "./MenuItem";

    export default {
      components: { MenuItem },
      data() {
        return {
          left: 0,
          top: 0,
          menu: [
            {
              name: "菜单项1",
              children: [
                {
                  name: "子菜单1-1"
                },
                {
                  name: "子菜单1-2"
                }
              ]
            },
            {
              name: "菜单项2"
            },
            {
              name: "菜单项3",
              children: [
                {
                  name: "子菜单3-1",
                  children: [
                    {
                      name: "子菜单3-1-1"
                    },
                    {
                      name: "子菜单3-1-2"
                    }
                  ]
                }
              ]
            }
          ]
        }
      },
      methods: {
        showMenu(e) {
          e.preventDefault();
          this.left = e.clientX;
          this.top = e.clientY;
        }
      }
    }
    </script>

    
  

下面是菜单项组件的代码,当鼠标进入菜单项时,我们设置 `showSubmenu` 为 `true` 显示下一级菜单;当鼠标移出菜单项时,我们设置 `showSubmenu` 为 `false` 隐藏下一级菜单。

  
    
   

    <script>
    import MenuItem from "./MenuItem";

    export default {
      components: { MenuItem },
      props: {
        item: {
          type: Object,
          required: true
        }
      },
      data() {
        return {
          showSubmenu: false
        }
      },
      computed: {
        hasChildren() {
          return Array.isArray(this.item.children) && this.item.children.length > 0;
        }
      },
      methods: {
        enter() {
          if (this.hasChildren) {
            setTimeout(() => {
              this.showSubmenu = true;
            }, 300);
          }
        },
        leave() {
          if (this.hasChildren) {
            this.showSubmenu = false;
          }
        }
      }
    }
    </script>