Vue.js nextTick inside computed property

Viewed 5958

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>
1 Answers
Related