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 相关文章推荐
通过ifame指向的页面高度调整iframe的高度
Oct 05 Javascript
用JavaScript实现UrlEncode和UrlDecode的脚本代码
Jul 23 Javascript
避免回车键导致的页面无意义刷新的解决方法
Apr 12 Javascript
使用CSS3的scale实现网页整体缩放
Mar 18 Javascript
Javascript中对象继承的实现小例
May 12 Javascript
jQuery实现微信长按识别二维码功能
Aug 26 Javascript
基于 Vue 的树形选择组件的示例代码
Aug 18 Javascript
Vue封装Swiper实现图片轮播效果
Feb 06 Javascript
浅谈react-router@4.0 使用方法和源码分析
Jun 04 Javascript
使用异步controller与jQuery实现卷帘式分页
Jun 18 jQuery
微信小程序表单验证WxValidate的使用
Nov 27 Javascript
使用vue判断当前环境是安卓还是IOS
Apr 12 Vue.js
一文读懂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
饭制《星际争霸》Mod:优化游戏机制 增加新单位
2017/07/02 星际争霸
php中get_headers函数的作用及用法的详细介绍
2013/04/27 PHP
PHP图像处理类库及演示分享
2015/05/17 PHP
使用PHP接受文件并获得其后缀名的方法
2015/08/05 PHP
编写PHP脚本清除WordPress头部冗余代码的方法讲解
2016/03/01 PHP
php 基础函数
2017/02/10 PHP
ThinkPHP使用getlist方法实现数据搜索功能示例
2017/05/08 PHP
PHP单元测试配置与使用方法详解
2019/12/27 PHP
2010年最佳jQuery插件整理
2010/12/06 Javascript
修改jquery.lazyload.js实现页面延迟载入
2010/12/22 Javascript
jQuery中parents()和parent()的区别分析
2014/10/28 Javascript
JS实现弹性漂浮效果的广告代码
2015/09/02 Javascript
Jquery实时监听input value的实例
2017/01/26 Javascript
javascript中BOM基础知识总结
2017/02/14 Javascript
js实现鼠标移动到图片产生遮罩效果
2017/10/21 Javascript
浅谈Koa服务限流方法实践
2017/10/23 Javascript
vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
2018/03/01 Javascript
详解Vue webapp项目通过HBulider打包原生APP
2018/06/29 Javascript
解决vue props 拿不到值的问题
2018/09/11 Javascript
javascript json字符串到json对象转义问题
2019/01/22 Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
2019/04/11 Javascript
Python学习_几种存取xls/xlsx文件的方法总结
2018/05/03 Python
对Python函数设计规范详解
2019/07/19 Python
如何利用Python开发一个简单的猜数字游戏
2019/09/22 Python
CSS3中Transition动画属性用法详解
2016/07/04 HTML / CSS
英国最大的宠物商店:Pets at Home
2019/04/17 全球购物
请写出 float x 与"零值"比较的 if 语句
2016/01/04 面试题
外贸主管求职简历的自我评价
2013/10/23 职场文书
什么是岗位职责
2013/11/12 职场文书
房地产营销策划方案
2014/02/08 职场文书
幼儿园端午节活动总结
2015/05/05 职场文书
风之谷观后感
2015/06/11 职场文书
初级职称评定工作总结
2015/08/13 职场文书
老干部局2015年度工作总结
2015/10/22 职场文书
Python初识逻辑与if语句及用法大全
2021/08/07 Python
win10拖拽文件时崩溃怎么解决?win10文件不能拖拽问题解决方法
2022/08/14 数码科技