I have "context menu" component. Computed properties top and left define menu position using $event property. But when I trying to open context menu, menu element is not rendered yet and top cannot be calculated without menu's offsetHeight, so I figured out to use some "nextTick hack" inside computed property:
top() {
if (!this.menuIsRendered) { // by default, menuIsRendered is false
this.$nextTick(() => {
this.menuIsRendered = true
})
return 0
}
... // menu element is rendered, calculate top value
},
Is this ok? I think there must be a better way to do this.
Also, full component code:
<template>
<div ref="menu" :style="{top: `${top}px`, left: `${left}px`}"
v-click-outside="close" @contextmenu.prevent v-if="show">
<slot></slot>
</div>
</template>
<script>
export default {
props: [
'show',
'event'
],
data() {
return {
menuIsRendered: null,
}
},
computed: {
top() {
if (!this.menuIsRendered) {
this.$nextTick(() => {
this.menuIsRendered = true
})
return 0
}
let top = this.event.y
let largestHeight = window.innerHeight - this.$refs.menu.offsetHeight - 25
return top > largestHeight ? largestHeight : top + 1
},
left() {
if (!this.menuIsRendered) {
return 0
}
let left = this.event.x
let largestWidth = window.innerWidth - this.$refs.menu.offsetWidth - 25
return left > largestWidth ? largestWidth : left + 1
},
},
methods: {
close() {
this.$emit('close')
},
}
}
</script>
Component usage:
<context-menu @close="close" :event="event" :show="show">
<div @click="doAction">Action</div>
<div @click="doAnotherAction">Another action</div>
</context-menu>