媒介
前段时间在用iView做个项目,个中须要运用自定义的右键菜单,然后去官网找了一下,发明有个Dropdown的组件,便想着能不能用来做个右键菜单的组件
你能够须要对iView有肯定的运用履历
尝试
Dropdown的运用大概是这个模样
<template>
<Dropdown>
<a href="javascript:void(0)">
下拉菜单
<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,详细代码能够参考这个堆栈