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 相关文章推荐
如何在Web页面上直接打开、编辑、创建Office文档
Mar 12 Javascript
从阿里妈妈发现的几个不错的表单验证函数
Sep 21 Javascript
整理一些JavaScript的IE和火狐的兼容性注意事项
Mar 17 Javascript
js中符号转意问题示例探讨
Aug 19 Javascript
浅谈jQuery页面的滚动位置scrollTop、scrollLeft
May 19 Javascript
简介JavaScript中POSITIVE_INFINITY值的使用
Jun 05 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
Feb 25 Javascript
jQuery中delegate()方法的用法详解
Oct 13 Javascript
vue基于Vue2.0和高德地图的地图组件实例
Apr 28 Javascript
vue项目刷新当前页面的三种方法
Dec 04 Javascript
JS实现点击生成UUID的方法完整实例【基于jQuery】
Jun 12 jQuery
使用vue重构资讯页面的实例代码解析
Nov 26 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基础知识回顾
2012/08/16 PHP
php+ajax实现无刷新数据分页的办法
2015/11/02 PHP
YII2.0框架行为(Behavior)深入详解
2019/07/26 PHP
JavaScript操作XML实例代码(获取新闻标题并分页,并分页)
2010/05/25 Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
用js实现控件的隐藏及style.visibility的使用
2013/06/14 Javascript
Jquery动态更改一张位图的src与Attr的使用
2013/07/31 Javascript
Jquery中的层次选择器与find()的区别示例介绍
2014/02/20 Javascript
JS通过分析userAgent属性来判断浏览器的类型及版本
2014/03/28 Javascript
通过JS来动态的修改url,实现对url的增删查改
2014/09/01 Javascript
jQuery处理json数据返回数组和输出的方法
2015/03/11 Javascript
javascript实现C语言经典程序题
2015/11/29 Javascript
jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
2015/12/31 Javascript
JS中call/apply、arguments、undefined/null方法详解
2016/02/15 Javascript
BootStrap中关于Select下拉框选择触发事件及扩展
2016/11/22 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
JavaScript实现shuffle数组洗牌操作示例
2019/01/03 Javascript
bootstrap-table formatter 使用vue组件的方法
2019/05/09 Javascript
[08:44]DOTA2发布会群星聚首 我们都是刀塔人
2014/03/21 DOTA
[01:00:11]DOTA2-DPC中国联赛 正赛 CDEC vs DLG BO3 第一场 2月7日
2021/03/11 DOTA
python实现ftp客户端示例分享
2014/02/17 Python
python实现爬取图书封面
2018/07/05 Python
使用tensorflow DataSet实现高效加载变长文本输入
2020/01/20 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
2020/02/27 Python
使用Python将语音转换为文本的方法
2020/08/10 Python
python实现图片转字符画的完整代码
2021/02/21 Python
法国珠宝店:CLEOR
2017/01/29 全球购物
行政经理的岗位职责
2013/11/23 职场文书
电脑教师的教学自我评价
2013/11/26 职场文书
社会学专业求职信
2014/02/24 职场文书
应届硕士毕业生自荐信
2014/05/26 职场文书
酒店采购员岗位职责
2015/04/03 职场文书
公司规章制度范本
2015/08/03 职场文书
煤矿隐患排查制度
2015/08/05 职场文书
初中思想品德教学反思
2016/02/24 职场文书
导游词之大雁塔景区
2019/09/17 职场文书