JS使用iView的Dropdown实现一个右键菜单


Posted in Javascript onMay 06, 2019

前言

前段时间在用iView做个项目,其中需要使用自定义的右键菜单,然后去官网找了一下,发现有个Dropdown的组件,便想着能不能用来做个右键菜单的组件

你可能需要对iView有一定的使用经验

尝试

Dropdown的使用大概是这个样子

<template>
 <Dropdown>
  <a href="javascript:void(0)" rel="external nofollow" >
   下拉菜单
   <Icon type="ios-arrow-down"></Icon>
  </a>
  <DropdownMenu slot="list">
   <DropdownItem>驴打滚</DropdownItem>
   <DropdownItem>炸酱面</DropdownItem>
   <DropdownItem disabled>豆汁儿</DropdownItem>
   <DropdownItem>冰糖葫芦</DropdownItem>
   <DropdownItem divided>北京烤鸭</DropdownItem>
  </DropdownMenu>
 </Dropdown>
</template>
<script>
 export default {

 }
</script>

发现有个触发元素slot,可以自定义的插入元素,我一想,只要把slot的内容设置为position: fixed,在右键的时候给它实时设置一下鼠标所在的位置不就行了嘛,然后一顿捣腾

<template>
 <Dropdown
  transfer
  placement="right-start"
  trigger="custom"
  :visible="currentVisible"
  @on-clickoutside="handleCancel"
 >
  <div :style="locatorStyle"></div>
  <DropdownMenu slot="list">
   <DropdownItem>驴打滚</DropdownItem>
   <DropdownItem>炸酱面</DropdownItem>
   <DropdownItem disabled>豆汁儿</DropdownItem>
   <DropdownItem>冰糖葫芦</DropdownItem>
   <DropdownItem divided>北京烤鸭</DropdownItem>
  </DropdownMenu>
 </Dropdown>
</template>
<script>
export default {
 data () {
  return {
   posX: 0,
   posY: 0,
   currentVisible: false
  }
 },
 computed: {
  locatorStyle () {
   return {
    position: 'fixed',
    left: `${this.posX}px`,
    top: `${this.posY}px`
   }
  }
 },
 methods: {
  handleContextmenu ({ button, clientX, clientY }) {
   if (button === 2) {
    if (this.posX !== clientX) this.posX = clientX
    if (this.posY !== clientY) this.posY = clientY
    this.currentVisible = true
   }
  },
  handleCancel () {
   this.currentVisible = false
  }
 },
 mounted () {
  document.addEventListener('contextmenu', this.handleContextmenu, true)
  document.addEventListener('mouseup', this.handleContextmenu, true)
 },
 destroyed () {
  document.removeEventListener('contextmenu', this.handleContextmenu, true)
  document.removeEventListener('mouseup', this.handleContextmenu, true)
 }
}
</script>

看上去很不错,然后兴高采烈地一试,发现无论怎么点,菜单始终定位在右上角

JS使用iView的Dropdown实现一个右键菜单

JS使用iView的Dropdown实现一个右键菜单

slot的元素位置确实发生了变化,然而菜单位置始终不变化

这可把我折腾了半天,也没弄出个结果。抱着 极不情愿 一探究竟的心情,我打开了Dropdown的源码

<template>
  <div
    :class="[prefixCls]"
    v-click-outside="onClickoutside"
    @mouseenter="handleMouseenter"
    @mouseleave="handleMouseleave">
    <!-- 注意此处 -->
    <div :class="relClasses" ref="reference" @click="handleClick" @contextmenu.prevent="handleRightClick"><slot></slot></div>
    <transition name="transition-drop">
      <Drop
        :class="dropdownCls"
        v-show="currentVisible"
        :placement="placement"
        ref="drop"
        @mouseenter.native="handleMouseenter"
        @mouseleave.native="handleMouseleave"
        :data-transfer="transfer"
        :transfer="transfer"
        v-transfer-dom><slot name="list"></slot></Drop>
    </transition>
  </div>
</template>
<script>
// 以下省略
</script>

可以看到标注的地方,slot的外层还有个div,而Dropdown的定位是依赖于外层的这个div的,所以无论你slot里的内容位置,在初始化之后再怎么变化,都不会影响到组件的位置了(也有可能是position: fixed的影响)

调整

发现slot外层的div有一个ref="reference"的属性

突然有了想法,我是不是可以直接通过Dropdown的refs直接把整个外层div替换掉,于是继续捣腾,改造了一下

<template>
 <Dropdown
  transfer
  placement="right-start"
  trigger="custom"
  ref="contextMenu"
  :visible="currentVisible"
  @on-clickoutside="handleCancel"
 >
  <DropdownMenu slot="list">
   <DropdownItem>驴打滚</DropdownItem>
   <DropdownItem>炸酱面</DropdownItem>
   <DropdownItem disabled>豆汁儿</DropdownItem>
   <DropdownItem>冰糖葫芦</DropdownItem>
   <DropdownItem divided>北京烤鸭</DropdownItem>
  </DropdownMenu>
 </Dropdown>
</template>
<script>
export default {
 data () {
  return {
   posX: 0,
   posY: 0,
   currentVisible: false,
   locator: null
  }
 },
 methods: {
  createLocator () {
   // 获取Dropdown
   const contextmenu = this.$refs.contextMenu
   // 创建locator
   const locator = document.createElement('div')
   locator.style.cssText = `position:fixed;left:${this.posX}px;top:${this.posY}px`
   document.body.appendChild(locator)
   // 将locator绑定到Dropdown的reference上
   contextmenu.$refs.reference = locator
   this.locator = locator
  },
  removeLocator () {
   if (this.locator) document.body.removeChild(this.locator)
   this.locator = null
  },
  handleContextmenu ({ button, clientX, clientY }) {
   if (button === 2) {
    if (this.posX !== clientX) this.posX = clientX
    if (this.posY !== clientY) this.posY = clientY
    if (this.trigger !== 'custom') {
     this.createLocator()
     this.currentVisible = true
    }
   }
  },
  handleCancel () {
   this.currentVisible = false
   this.removeLocator()
  }
 },
 mounted () {
  document.addEventListener('contextmenu', this.handleContextmenu, true)
  document.addEventListener('mouseup', this.handleContextmenu, true)
 },
 destroyed () {
  document.removeEventListener('contextmenu', this.handleContextmenu, true)
  document.removeEventListener('mouseup', this.handleContextmenu, true)
 }
}
</script>

根据鼠标的位置实时创建一个position: fixed的div,通过给Dropdown添加ref属性,获取到Dropdown对象之后再通过$ref属性将div赋值到reference

大功告成,现在Dropdown会根据鼠标所在的位置出现啦

JS使用iView的Dropdown实现一个右键菜单

最后把一些点击的回调方法补全,就是一个像样的右键菜单组件了

当然作为一个可以复用的组件,还需要把一些通用逻辑再提取出来,以及补全一些常用的API,具体代码可以参考这个仓库

总结

以上所述是小编给大家介绍的JS使用iView的Dropdown实现一个右键菜单,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
jquery实现input输入框实时输入触发事件代码
Jan 28 Javascript
Jquery之Bind方法参数传递与接收的三种方法
Jun 24 Javascript
setinterval()与clearInterval()JS函数的调用方法
Jan 21 Javascript
JavaScript搜索字符串并将搜索结果返回到字符串的方法
Apr 06 Javascript
js绘制圆形和矩形的方法
Aug 05 Javascript
javascript实现标签切换代码示例
May 22 Javascript
js拼接html字符串的注意事项
Oct 13 Javascript
js实现移动端微信页面禁止字体放大
Feb 16 Javascript
ES6字符串模板,剩余参数,默认参数功能与用法示例
Apr 06 Javascript
React 高阶组件入门介绍
Jan 11 Javascript
angular基于ng-alain定义自己的select组件示例
Feb 23 Javascript
vue.js中使用微信扫一扫解决invalid signature问题(完美解决)
Apr 11 Javascript
一文读懂ES7中的javascript修饰器
May 06 #Javascript
JavaScript中AOP的实现与应用
May 06 #Javascript
使用 vue 实现灭霸打响指英雄消失的效果附demo
May 06 #Javascript
vue如何截取字符串
May 06 #Javascript
用vscode开发vue应用的方法步骤
May 06 #Javascript
微信小程序合法域名配置方法
May 06 #Javascript
手把手教你使用TypeScript开发Node.js应用
May 06 #Javascript
You might like
PHP 获取目录下的图片并随机显示的代码
2009/12/28 PHP
理解PHP中的Session及对Session有效期的控制
2016/01/08 PHP
php中get_object_vars()在数组的实例用法
2021/02/22 PHP
鼠标图片振动代码
2006/07/06 Javascript
基于jquery的划词搜索实现(备忘)
2010/09/14 Javascript
javascript实现汉字转拼音代码分享
2015/04/20 Javascript
JS中生成随机数的用法及相关函数
2016/01/09 Javascript
第二章之Bootstrap 页面排版样式
2016/04/25 Javascript
用js实现放大镜的效果的简单实例
2016/05/23 Javascript
浅谈JavaScript 浏览器对象
2016/06/03 Javascript
浅谈javascript中遇到的字符串对象处理
2016/11/18 Javascript
详解js的事件处理函数和动态创建html标记方法
2016/12/16 Javascript
jquery实现的table排序功能示例
2017/03/10 Javascript
JavaScript中splice与slice的区别
2017/05/09 Javascript
vue+element实现批量删除功能的示例
2018/02/28 Javascript
如何为你的JavaScript代码日志着色详解
2019/04/08 Javascript
vue2.0自定义指令示例代码详解
2019/04/25 Javascript
Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
2019/04/26 Javascript
vue draggable resizable 实现可拖拽缩放的组件功能
2019/07/15 Javascript
Python字符串格式化输出方法分析
2016/04/13 Python
python3批量删除豆瓣分组下的好友的实现代码
2016/06/07 Python
代码讲解Python对Windows服务进行监控
2018/02/11 Python
pygame游戏之旅 添加游戏界面按键图形
2018/11/20 Python
python 划分数据集为训练集和测试集的方法
2018/12/11 Python
python匹配两个短语之间的字符实例
2018/12/25 Python
PyTorch搭建多项式回归模型(三)
2019/05/22 Python
Python中asyncio模块的深入讲解
2019/06/10 Python
Python脚本实现Zabbix多行日志监控过程解析
2020/08/26 Python
维多利亚的秘密官方旗舰店:VICTORIA’S SECRET
2018/04/02 全球购物
ColourPop美国官网:卡拉泡泡,洛杉矶彩妆品牌
2019/04/28 全球购物
英国123鲜花网站:123 Flowers
2019/07/07 全球购物
党课培训主持词
2014/04/01 职场文书
公司人事专员岗位职责
2014/08/11 职场文书
个人先进事迹总结
2015/02/26 职场文书
求职信:会计求职的写作技巧
2019/04/24 职场文书
Python面向对象之成员相关知识总结
2021/06/24 Python