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 事件对象属性小结
Apr 27 Javascript
window.name代替cookie的实现代码
Nov 28 Javascript
event对象获取方法总结在google浏览器下测试
Nov 03 Javascript
页面图片浮动左右滑动效果的简单实现案例
Feb 10 Javascript
javascript的理解及经典案例分析
May 20 Javascript
详解vue.js组件化开发实践
Dec 14 Javascript
JS常用正则表达式总结【经典】
May 12 Javascript
通俗解释JavaScript正则表达式快速记忆
Aug 23 Javascript
详细介绍RxJS在Angular中的应用
Sep 23 Javascript
详解自定义ajax支持跨域组件封装
Feb 08 Javascript
解决layui中的form表单与button的点击事件冲突问题
Aug 15 Javascript
实例讲解React 组件
Jul 07 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实现获取文件mime类型的方法
2015/02/11 PHP
JavaScript中的new的使用方法与注意事项
2007/05/16 Javascript
jquery tools之tabs 选项卡/页签
2009/07/25 Javascript
jquery 删除cookie失效的解决方法
2013/11/12 Javascript
基于javascript实现表格的简单操作
2016/05/21 Javascript
JS从一组数据中找到指定的单条数据的方法
2016/06/02 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
2016/12/18 Javascript
JS 在数组指定位置插入/删除数据的方法
2017/01/12 Javascript
Angular中点击li标签实现更改颜色的核心代码
2017/12/08 Javascript
JS实现电话号码的字母组合算法示例
2019/02/26 Javascript
微信小程序 setData 对 data数据影响问题
2019/04/18 Javascript
JavaScript 替换所有匹配内容及正则替换方法
2020/02/12 Javascript
js制作提示框插件
2020/12/24 Javascript
在树莓派2或树莓派B+上安装Python和OpenCV的教程
2015/03/30 Python
Python 列表(List) 的三种遍历方法实例 详解
2017/04/15 Python
Tensorflow之构建自己的图片数据集TFrecords的方法
2018/02/07 Python
解决python3 urllib 链接中有中文的问题
2018/07/16 Python
详解Django中类视图使用装饰器的方式
2018/08/12 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
2019/08/20 Python
python实现从ftp服务器下载文件
2020/03/03 Python
python pandas dataframe 去重函数的具体使用
2020/07/20 Python
Python使用socket模块实现简单tcp通信
2020/08/18 Python
Python中的面向接口编程示例详解
2021/01/17 Python
selenium+超级鹰实现模拟登录12306
2021/01/24 Python
html5开发三八女王节表白神器
2018/03/07 HTML / CSS
夏威夷航空官网:Hawaiian Airlines
2016/09/11 全球购物
巴西最大的在线约会网站:ParPerfeito
2018/07/11 全球购物
法国购买隐形眼镜和眼镜网站:Optical Center
2019/10/08 全球购物
公务员职务工作的自我评价
2013/11/01 职场文书
捐赠仪式主持词
2014/03/19 职场文书
合作意向书格式及范文
2014/03/31 职场文书
推荐信格式要求
2014/05/09 职场文书
党的群众路线教育实践活动个人整改措施落实情况
2014/11/04 职场文书
莫言诺贝尔获奖感言(全文)
2015/07/31 职场文书
java多态注意项小结
2021/10/16 Java/Android
Spring Boot 底层原理基础深度解析
2022/04/03 Java/Android