vue项目右键菜单实现新标签页及新窗口打开

5,237 阅读2分钟

前言: 近日接到一个需求,Vue管理后台菜单导航实现类似多页面应用右键在新标签页中打开和新窗口打开的效果,如下图所示:

实现思路:以上效果是浏览器自身行为,应该是抓取到当前页面容器中a标签并找到href属性生成,但在项目中并不能将导航菜单换成a链接实现,于是想到了通过JS鼠标右键事件模拟生成右键菜单。

右键事件作用于动态生成的菜单标签<span />上, 而且菜单组件为递归组件,便想到利用指令实现,基于此找到了一棵救命稻草v-contextmenu,指令详情请参看

www.npmjs.com/package/v-c…

用法很简单,下边是一个简单的例子:

import contentmenu from 'v-contextmenu'
import 'v-contextmenu/dist/index.css'
Vue.use(contentmenu)`

<v-contextmenu ref="contextmenu">
    <v-contextmenu-item>菜单</v-contextmenu-item>
</v-contextmenu>
<div v-contextmenu:contextmenu></div>

根组件VContextmenu有一个 contextmenu 事件,该事件鼠标右键时触发,回调参数为触发 contextmenu 事件区域的 vnode,根据vnode节点可以找到target上属性值,根据属性值可以知道动态菜单的名字和路由。下面代码中link属性即为绑定的动态菜单名字。子组件VContextmenuItem有click 事件,回调参数有两个,第一个参数是 vm, 第二个参数是该菜单的 event。 实际业务右键菜单组件实现代码如下:

    <menu-item :name="getNameOrHref(item)" :link="item.name" v-contextmenu:contextmenu>

    <v-contextmenu ref="contextmenu" @contextmenu="menuRightChange">
        <v-contextmenu-item @click="openInBlank">在新标签页中打开</v-contextmenu-item>
        <v-contextmenu-item @click="openInWindow">在新窗口打开链接</v-contextmenu-item>
        <v-contextmenu-item @click="toHome">跳转至首页</v-contextmenu-item>
        <v-contextmenu-item @click="reload">刷新当前页面</v-contextmenu-item>
    </v-contextmenu>

contextmenu 事件回调将得到的那么属性赋值给一个变量,实现如下:

    menuRightChange (ins) {
        if (ins.data.attrs && ins.data.attrs.link) {
            this.currentLink = ins.data.attrs.link;
        }
    }

新标签页中打开效果实现

编程式导航 this.$router.pushthis.$router.go 在vue2.0以后版本中不支持新窗口中打开属性, 这个时候就需要使用this.$router.resolve来实现,解析后可以得到location、router、href等目标路由的信息,得到href属性就可以使用window.open开新窗口了。

window.open接收四个可选参数,分别为打开指定的页面的URL、指定target属性或窗口的名称、一个逗号分隔的项目列表、装载或替换当前条目。

window.open([URL],[name],[specs],[replace])

根据刚才得到的href属性和_blank属性即可实现,代码如下:

    let routeUrl = this.$router.resolve({
        name: this.currentLink
    });
    window.open(routeUrl.href, '_blank');

新窗口中打开效果实现

在新窗口中实现原理与新标签页中打开实现方式相同。相比新标签页中打开仅仅多了一个specs参数,实现如下:

openWindow (url, title, w, h) {
  const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
  const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;
  const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ?
  document.documentElement.clientWidth : screen.width;
  const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ?
  document.documentElement.clientHeight : screen.height;
  const left = ((width / 2) - (w / 2)) + dualScreenLeft
  const top = ((height / 2) - (h / 2)) + dualScreenTop
  const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left)
  if (window.focus) {
    newWindow.focus()
  }
}
// 新窗口打开
openInWindow () {
  let routeUrl = this.$router.resolve({
    name: this.currentLink
  });
  this.openWindow(routeUrl.href)
}

至此效果基本实现,实现效果如图:

最后,谢谢各位,与此共勉之。