做一个 Vue 右键菜单组件

Posted Himmelbleu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做一个 Vue 右键菜单组件相关的知识,希望对你有一定的参考价值。

取消原生右键事件

在 main.ts 函数中取消浏览器默认右键菜单:

window.oncontextmenu = () => 
  return false;
;

组件模板

做一个不同区域右键点击之后不同菜单项的组件,创建组件模板:

<!-- ContextMenu -->

<div ref="menu" class="l-menu">
    <slot />
    <Teleport to="#l-menu-container">
      <div
        ref="panel"
        :id="\'l-menu__panel__\' + milliseconds"
        :>
        <div ref="head" class="l-menu__head">
          <div class="l-menu__title">
            <slot name="title" />
          </div>
          <div @click="panel.style.display = \'none\'">
            <i-ep-close />
          </div>
        </div>
        <div class="l-menu__main">
          <slot name="content" />
        </div>
      </div>
    </Teleport>
  </div>

模板中使用了 Teleport,需要把这一块传递到页面中 l-menu-container 元素中去,这个元素在 body 下,意思是我的右键菜单组件呼出的面板不受父组件的样式影响,包括移动的范围限制、背景颜色等,这些继承父元素样式都需要避免。

组件 setup

需要获取组件模板的一些引用:

// ContextMenu setup
const menu = ref<HTMLElement>();
const head = ref<HTMLElement>();
const panel = ref<HTMLElement>();
const milliseconds = new Date().getMilliseconds();
const  x, y  = useDraggable(head);

onMounted(() => 
  menu.value.onmouseup = e => 
    if (e.button == 2) 
      const container = document.querySelector("#l-menu-container");
      const menuId = container.getAttribute("menu-id");
      menuId && (document.getElementById(`l-menu__panel__$menuId`).style.display = "none");
      container.setAttribute("menu-id", `$milliseconds`);
      panel.value.style.left = `$e.clientXpx`;
      panel.value.style.top = `$e.clientYpx`;
      panel.value.style.display = "block";
    
  ;
);

鼠标按下放开事件,判断鼠标是左键还是右键,button 为 2 代表右键,右键点击之后需要移除上一个开启的面板,在 body 下的 #l-menu-container 元素上添加一个记录上一次面板的 id。

实现右键出来之后的菜单面板自由地在窗口中移动,直接借助 VueUse useDraggable 函数:

const  x, y  = useDraggable(head);

得到鼠标移动的 x 和 y 值,通过绑定 style 对 left 和 top 进行设置,就可以实现自由移动。

使用组件

该组件有三个插槽,一个默认插槽,两个具名插槽。具名 content 插槽是菜单内容,默认插槽是能呼出右键菜单面板的区域,哪个区域能呼出就在外面套一层 ContextMenu 组件:

<ContextMenu>
  <div class="item">
    hello
  </div>
  <template #title>样式设置</template>
  <template #content>
    <BoxSetting />
  </template>
</ContextMenu>

实现效果

以上是关于做一个 Vue 右键菜单组件的主要内容,如果未能解决你的问题,请参考以下文章

vue中,右键菜单组件v-contextmenu的使用

Vue2的右键弹出菜单(vue-contextmenu)

vue实现页面权限中的菜单配置

vue组件递归——级联菜单的实现

vue仿美团侧边菜单组件

vue + elementUI 表格右键弹出菜单