您的位置:

Vue右键菜单详解

一、Vue右键菜单组件

Vue右键菜单是一个常用的功能组件,它用于在鼠标右键点击时弹出一个自定义的菜单。Vue的官方文档中并没有对右键菜单进行提及,但是我们可以借助第三方库element-ui中的ContextMenu组件来实现。

<template>
  <div>
    <el-button@contextmenu.native.prevent)="handleContextMenu">右键点击我</el-button>
    <el-context-menuref="contextMenu">
      <el-menu>
        <el-menu-item>上传文件</el-menu-item>
        <el-menu-item>新建文件夹</el-menu-item>
      </el-menu>
    </el-context-menu>
  </div>
</template>

<script>
import { ElButton, ElContextMenu, ElMenuItem, ElMenu } from 'element-ui';
export default {
  components: {
    ElButton,
    ElContextMenu,
    ElMenuItem,
    ElMenu,
  },
  data() {
    return {
      contextMenu: null,
    }
  },
  methods: {
    handleContextMenu(event) {
      event.preventDefault();
      this.contextMenu.handleContextmenu(event);
    }
  }
}
</script>

在上面的例子中,我们引入了element-ui库,并使用其中的ElButton, ElContextMenu, ElMenuItem, ElMenu组件来实现一个右键菜单。我们在页面中放置一个ElButton按钮,在其上添加了一个contextmenu.native.prevent事件监听,当我们在该按钮上右键点击时,该事件会被触发,并且我们通过调用handleContextMenu方法,让右键菜单弹出来。在ElContextMenu组件中,我们放置了一个ElMenu组件,并且给其添加了两个ElMenuItem组件,这两个菜单项就是我们的右键菜单选项。

二、Vue右键菜单怎么隐藏

当右键菜单弹出后,用户有可能会通过点击其他地方来关闭它,或者进行特定操作后需要关闭它。要关闭右键菜单,我们可以在Vue组件中保存一个ContextMenu实例,并且通过调用其隐藏方法来关闭该右键菜单。

<template>
  <div>
    <el-button@contextmenu.native.prevent)="handleContextMenu">右键点击我</el-button>
    <el-context-menuref="contextMenu">
      <el-menu>
        <el-menu-item>上传文件</el-menu-item>
        <el-menu-item>新建文件夹</el-menu-item>
      </el-menu>
    </el-context-menu>
  </div>
</template>

<script>
import { ElButton, ElContextMenu, ElMenuItem, ElMenu } from 'element-ui';
export default {
  components: {
    ElButton,
    ElContextMenu,
    ElMenuItem,
    ElMenu,
  },
  data() {
    return {
      contextMenu: null,
    }
  },
  methods: {
    handleContextMenu(event) {
      event.preventDefault();
      this.contextMenu.handleContextmenu(event);
      document.addEventListener('click', this.handleDocumentClick);
    },
    handleDocumentClick() {
      this.contextMenu.hide();
      document.removeEventListener('click', this.handleDocumentClick);
    }
  }
}
</script>

在上面的例子中,我们通过document.addEventListener()方法来监听document的click事件。当用户在页面中点击其他地方时,该事件会被触发。同时,我们也通过document.removeEventListener()方法来移除监听器。在handleContextMenu方法中,我们除了调用handleContextmenu方法打开右键菜单外,还添加了一个click事件监听器,该监听器会在handleContextMenu方法调用后加入。

当用户点击页面其他地方时,handleDocumentClick方法会被调用。在这个方法中,我们调用了contextMenu实例的hide()方法来隐藏右键菜单,同时移除click事件监听器。

三、Vue右键菜单指令

除了在组件中使用右键菜单功能,我们还可以通过Vue指令来实现右键菜单功能。

<template>
  <div>
    <divv-right-click-menu="menuOptions">右键点击我</divv-right-click-menu>
  </div>
</template>

<script>
import DivvRightClickMenu from './divv-right-click-menu';
export default {
  directives: {
    DivvRightClickMenu,
  },
  data() {
    return {
      menuOptions: [
        {
          name: '上传文件',
          action: () => {
            console.log('upload file');
          },
        },
        {
          name: '新建文件夹',
          action: () => {
            console.log('create folder');
          },
        },
      ],
    }
  },
}
</script>

在上面的例子中,我们定义了一个指令DivvRightClickMenu,并且在页面中使用它。该指令会在被绑定的元素上添加一个contextmenu监听事件。同时,我们在数据中定义了一个menuOptions数组,其中包含了菜单选项的名称和执行方法。当用户右键点击指定元素时,菜单会弹出来,当菜单选项被选中时,指定的方法将会被执行。

四、Vue右键菜单组件element

除了第三方库element-ui提供的ContextMenu组件之外,Vue的其他第三方库中也可能会包含右键菜单组件。

<template>
  <div>
    <b-right-click-menu@click-item="(index) => handleClick(index)">
      <b-menu-item v-for="(item, index) in menuOptions" :key="index">{{ item.name }}</b-menu-item>
    </b-right-click-menu>
  </div>
</template>

<script>
import { BRightClickMenu, BMenuItem } from 'bootstrap-vue';
export default {
  components: {
    BRightClickMenu,
    BMenuItem,
  },
  data() {
    return {
      menuOptions: [
        {
          name: '上传文件',
        },
        {
          name: '新建文件夹',
        },
      ],
    }
  },
  methods: {
    handleClick(index) {
      const menuItem = this.menuOptions[index];
      console.log(`click ${menuItem.name}`);
    },
  },
}
</script>

在上面的例子中,我们使用了Bootstrap Vue库中的BRightClickMenu和BMenuItem组件来实现右键菜单功能。我们在页面中放置了一个BRightClickMenu组件,并且在其内部放置了多个BMenuItem组件,这些组件就是我们的右键菜单选项。我们可以通过@click-item事件来监听右键菜单选项的点击事件,当用户点击时,handleClick方法会被调用,我们通过查找当前选中菜单的索引,来执行指定的方法。

五、Vue右键菜单被覆盖

在使用右键菜单时,我们有时会遇到被菜单本身或其他弹出组件覆盖住的情况。为了解决这个问题,我们可以通过通过计算菜单在页面中的位置,并在显示菜单时将其放置在最顶部。

// 组件部分
<template>
  <div>
    <el-button@contextmenu.native.prevent)="handleContextMenu">右键点击我</el-button>
    <el-context-menuv-if="visible" ref="contextMenu">
      <el-menu>
        <el-menu-item>上传文件</el-menu-item>
        <el-menu-item>新建文件夹</el-menu-item>
      </el-menu>
    </el-context-menu>
  </div>
</template>

<script>
import { ElButton, ElContextMenu, ElMenuItem, ElMenu } from 'element-ui';
export default {
  components: {
    ElButton,
    ElContextMenu,
    ElMenuItem,
    ElMenu,
  },
  data() {
    return {
      visible: false,
    }
  },
  methods: {
    handleContextMenu(event) {
      event.preventDefault();
      this.visible = true;
      const contextMenu = this.$refs.contextMenu.$el;
      contextMenu.style.display = 'block';
      const x = event.clientX;
      const y = event.clientY;
      const menuWidth = contextMenu.offsetWidth;
      const menuHeight = contextMenu.offsetHeight;
      const screenWidth = window.innerWidth;
      const screenHeight = window.innerHeight;
      if (x + menuWidth > screenWidth) {
        contextMenu.style.left = `${screenWidth - menuWidth}px`;
      } else {
        contextMenu.style.left = `${x}px`;
      }
      if (y + menuHeight > screenHeight) {
        contextMenu.style.top = `${screenHeight - menuHeight}px`;
      } else {
        contextMenu.style.top = `${y}px`;
      }
      document.addEventListener('click', this.handleDocumentClick);
    },
    handleDocumentClick() {
      this.$refs.contextMenu.hide();
      this.visible = false;
      document.removeEventListener('click', this.handleDocumentClick);
    }
  }
}
</script>

在上面的例子中,我们在handleContextMenu方法中添加了一些代码,用于计算菜单应该出现的位置。我们通过获取点击事件的clientX和clientY来获取菜单应该出现的坐标,然后获取菜单的宽度和高度,以及屏幕的宽度和高度。通过这些变量的计算,我们可以计算出菜单应当出现的位置,并将其放置在屏幕的最顶部。同时,我们还有将visible变量保存为true,这样我们就可以在组件中判断菜单是否正在显示,并正确隐藏它。