[vue2]自定义指令右键菜单

881 阅读2分钟

说明

使用vue自定义指令特性,来完成对某个item鼠标右击形成自定义菜单

参考地址

cn.vuejs.org/v2/guide/cu…

几个钩子函数

  1. bind: 只调用一次,第一次绑定元素使用,做初始化操作
  2. inserted:被绑定元素掺入父节点时调用
  3. update: VNode更新时调用
  4. unbind:调用一次,指令和元素解绑时调用

钩子函数中参数

  • el: 指令当前所绑定元素,可直接才做dom(基本会用到)
  • bind(只读): 调用一次,做初始化设置
    • name: 指令名字,不包含v-, 比如v-loading,这里就是loading
    • value: 指定中绑定值
    • arg: 传给指令参数,如v-my-directive:foo 中,参数为 "foo"
    • modifiers: 一个包含修饰符对象,如v-loading.fullscreen.lock为{ fullscreen: true, lock: true },这在扩张指令功能时有很重作用
  • vnode(只读): vue编译生成虚拟dom节点,通过vnode.context可以获取vm实例对象
  • oldVnode(只读):上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用.

vue中使用自定义指令,要善于利用H5中的dataset新特性

具体步骤

  • 先写一个组件,用来布局右侧菜单的页面样式,同时设置响应式数据rightMenu,提供包含4个数据,status(字符串)/top(字符串)/left(字符串)/menus(数组)
<template>
  <div class="rightClickMenu-box flex-row"
      :style="{
      display: rightMenu.status,
      top: rightMenu.top,
      left: rightMenu.left
      }">
  <ul>
    <li class="cp" v-for="item in rightMenu.menus" :key="item.id" @click="item.callBack(item.graphId, item.graphName)">
      <div class="flex-row flex-h-sb">
        <div style="width: 30%;">
          <img :src="item.icon" alt="item.text" style="width: 16px;height: 16px;" />
        </div>
        <div class="flex-row flex-v-center" style="text-align: left;width: 70%;">{{ item.text }}</div>
      </div>
    </li>
  </ul>
  </div>
</template>
  • 写自定义右击菜单指令
import Vue from 'vue'
import store from '@/store'

// 自定义右击菜单指令
Vue.directive('rightClick', {
  bind: function (el, binding) {
    // oncontextmenu是源生鼠标右击事件,默认会弹出浏览器自带右键菜单
    el.oncontextmenu = function(e) {
      const currentModule = store.state.currentModule
      if (currentModule !== 'modelFactoryModel') return // 只有[模型]模块,左侧树才能右击自定义菜单
      // 处理菜单名称
      const { value: menus } = binding
      if (menus.length === 0) return
      const graphId = e.target.dataset.graphId // 在使用rightClick节点中配置对应graphId的值
      const graphName = e.target.dataset.graphName // 在使用rightClick节点中配置对应graphName的值
      // 鼠标位置
      const X = e.clientX
      const Y = e.clientY
      menus.forEach(item => {
        item.graphId = graphId
        item.graphName = graphName
      })
      store.commit('updateRightMenuStatus', {
        status: 'block',
        left: `${X}px`,
        top: `${Y}px`,
        menus
      })
      return false // 阻止默认行为,阻止浏览器自带右键菜单的弹出
    }
  }
})

  • 在对应item节点dom上使用v-right-click指令,在dom中使用html5中dataset技巧,来处理参数传递的问题
<div v-right-click="menus"
     :data-graph-id="item.id" :data-graph-name="item.name"
     class="ml8 cm ops-node" style="color: #666666;"
     :draggable="nodeType === 'model' ? false : true"
     @dragstart="handleDragstart" @dragend="handleDragEnd($event, item)">
    {{ item.name }}
</div>