JS使用iView的Dropdown实现一个右键菜单
前段时间在用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>
看上去很不错,然后兴高采烈地一试,发现无论怎么点,菜单始终定位在右上角
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会根据鼠标所在的位置出现啦
最后把一些点击的回调方法补全,就是一个像样的右键菜单组件了
当然作为一个可以复用的组件,还需要把一些通用逻辑再提取出来,以及补全一些常用的api,具体代码可以参考这个仓库
总结
以上所述是小编给大家介绍的js使用iview的dropdown实现一个右键菜单,希望对大家有所帮助
上一篇: 浅谈C#中的值类型和引用类型