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 相关文章推荐
单独使用CKFinder选择图片的方法
Aug 21 Javascript
Asp.net下使用Jquery Ajax传送和接收DataTable的代码
Sep 12 Javascript
5个书写JavaScript代码的坏习惯,看看你中枪了没?
Nov 06 Javascript
javascript为按钮注册回车事件(设置默认按钮)的方法
May 09 Javascript
javascript检测两个数组是否相似
May 19 Javascript
JavaScript实现点击按钮就复制当前网址
Dec 14 Javascript
基于Javascript实现弹出页面效果
Jan 01 Javascript
Node使用Sequlize连接Mysql报错:Access denied for user ‘xxx’@‘localhost’
Jan 03 Javascript
jQuery封装animate.css的实例
Jan 04 jQuery
vue中倒计时组件的实例代码
Jul 06 Javascript
说说如何在Vue.js中实现数字输入组件的方法
Jan 08 Javascript
layer.open组件获取弹出层页面变量、函数的实例
Sep 25 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 404错误页面实现代码
2009/06/22 PHP
php中修改浏览器的User-Agent来伪装你的浏览器和操作系统
2011/07/29 PHP
php中使用exec,system等函数调用系统命令的方法(不建议使用,可导致安全问题)
2012/09/07 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
PHP统一页面编码避免乱码问题
2015/04/09 PHP
thinkphp自带验证码全面解析
2016/09/18 PHP
PHP 信号管理知识整理汇总
2017/02/19 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
用 Javascript 验证表单(form)中的单选(radio)值
2009/09/08 Javascript
JQuery扩展插件Validate 2通过参数设置验证规则
2011/09/05 Javascript
JavaScript字符串插入、删除、替换函数使用示例
2013/07/25 Javascript
js+ajax实现获取文件大小的方法
2015/12/08 Javascript
select隐藏选中值对应的id,显示其它id的简单实现方法
2016/08/25 Javascript
jquery动态添加文本并获取值的方法
2016/10/12 Javascript
微信小程序 网络API Websocket详解
2016/11/09 Javascript
深入理解react-router@4.0 使用和源码解析
2017/05/23 Javascript
如何抽象一个Vue公共组件
2017/10/17 Javascript
JS实现倒序输出的几种常用方法示例
2019/04/13 Javascript
Vue-cli4 配置 element-ui 按需引入操作
2020/09/11 Javascript
[57:41]Secret vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python中struct模块对字节流/二进制流的操作教程
2017/01/21 Python
python如何求解两数的最大公约数
2018/09/27 Python
Python使用import导入本地脚本及导入模块的技巧总结
2019/08/07 Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
2019/10/17 Python
Python中filter与lambda的结合使用详解
2019/12/24 Python
解决Pytorch 加载训练好的模型 遇到的error问题
2020/01/10 Python
django模型动态修改参数,增加 filter 字段的方式
2020/03/16 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
Python无损压缩图片的示例代码
2020/08/06 Python
ghd法国官方网站:英国最受欢迎的美发工具品牌
2019/04/18 全球购物
好书伴我成长演讲稿
2014/05/14 职场文书
小学校本培训方案
2014/06/06 职场文书
2015年护士长个人工作总结
2015/04/24 职场文书
2015年国庆晚会主持词
2015/07/01 职场文书
高中生物教学反思
2016/02/20 职场文书
Canvas绘制像素风图片的示例代码
2021/09/25 HTML / CSS