组件代码
<template>
<transition :name="transitionName">
<div
class="gi-content-menu"
ref="contentMenu"
:style="[contentMenuStyle]"
v-show="getShow"
v-clickoutside="handleClose"
>
<slot></slot>
</div>
</transition>
</template>
<script>
export default {
name: 'GiContentMenu',
props: {
value: {
type: Boolean,
default: false
},
axis: {
type: Object,
default: () => {}
},
width: {
type: String,
default: '100px'
},
height: {
type: String,
default: 'auto'
}
},
data() {
return {
transitionName: '',
contentMenuHeight: 0,
contentMenuStyle: {}
}
},
watch: {
'axis.x'() {
this.$nextTick(() => {
this.getShow = false
setTimeout(async () => {
this.getStyle()
this.getShow = true
}, 0)
})
},
'axis.y'() {
this.$nextTick(() => {
this.contentMenuHeight = this.$refs['contentMenu'].offsetHeight
this.transitionName =
this.axis.y > window.innerHeight - this.contentMenuHeight ? 'el-zoom-in-bottom' : 'el-zoom-in-top'
this.getShow = false
setTimeout(() => {
this.getStyle()
this.getShow = true
}, 0)
})
}
},
computed: {
getShow: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
methods: {
getStyle() {
const obj = {}
obj.left = this.axis.x + 2 + 'px'
if (this.axis.y > window.innerHeight - this.contentMenuHeight) {
obj.bottom = window.innerHeight - this.axis.y + 'px'
} else {
obj.top = this.axis.y + 2 + 'px'
}
obj.width = this.width
obj.height = this.height
obj['z-index'] = 999
this.contentMenuStyle = obj
},
handleClose() {
this.$emit('input', false)
}
}
}
</script>
<style lang="scss" scoped>
.gi-content-menu {
background: #fff;
position: fixed;
z-index: -999;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
border-radius: 4px;
}
</style>
组件所用指令
import Vue from 'vue'
Vue.directive('clickoutside', {
bind(el, binding, vnode) {
function documentHandler(e) {
if (el.contains(e.target)) {
return false
}
if (binding.expression) {
binding.value(e)
}
}
el.__vueClickOutside__ = documentHandler
document.addEventListener('click', documentHandler)
},
update() {},
unbind(el, binding) {
document.removeEventListener('click', el.__vueClickOutside__)
delete el.__vueClickOutside__
}
})
使用
<GiContentMenu :axis="axis" v-model="showContentMenu">
<div>
<section>新增</section>
<section>编辑</section>
<section>重命名</section>
<section>删除</section>
</div>
<GiContentMenu>
