yuche / vue-strap

Bootstrap components built with Vue.js
http://yuche.github.io/vue-strap/
MIT License
4.71k stars 935 forks source link

"TypeError: popover is null" issue in firefox (with solution) #510

Open OneOfTheWorld opened 6 years ago

OneOfTheWorld commented 6 years ago

Branch: master Error description: `

Container Size/Type: {{cntrSizeType}}
{{cntrSizeType}}
  </div>`

as the above code, I want to use Tooltip.vue to show some tips to user, but found that In chrome, the tooltip can always show rightly, but in firefox the tooltip sometimes can not show rightly: Right one: image

Wrong one: image and the console output the following error: image

OneOfTheWorld commented 6 years ago

Reason: Issue file: vue-strap/src/Tooltip.vue

<div v-el:popover v-if="show" style="display:block;"
    :class="['tooltip',placement]"
    :transition="effect"

Issue file: vue-strap/src/utils/popoverMixins.js

toggle (e) {
      if (e && this.trigger === 'contextmenu') e.preventDefault()
      if (!(this.show = !this.show)) { return }
      setTimeout(() => {
        const popover = this.$els.popover
        const trigger = this.$els.trigger.children[0]
        switch (this.placement) {
          case 'top' :
            this.position.left = trigger.offsetLeft - popover.offsetWidth / 2 + trigger.offsetWidth / 2
            this.position.top = trigger.offsetTop - popover.offsetHeight
            break
.........

when call toggle function, once set the "this.show = true", then the VUE will take time to render the popover div , but In firefox the setTimeout may execute before the popover div rendered, so it will cause the popover el null error.

OneOfTheWorld commented 6 years ago

Solution Target File: vue-strap/src/utils/popoverMixins.js

in toggle function, change setTimeout function to the following:

Vue.nextTick(() => {
  const popover = this.$els.popover
  const trigger = this.$els.trigger.children[0]
  switch (this.placement) {
    case 'top' :
      this.position.left = trigger.offsetLeft - popover.offsetWidth / 2 + trigger.offsetWidth / 2
      this.position.top = trigger.offsetTop - popover.offsetHeight
      break
    case 'left':
      this.position.left = trigger.offsetLeft - popover.offsetWidth
      this.position.top = trigger.offsetTop + trigger.offsetHeight / 2 - popover.offsetHeight / 2
      break
    case 'right':
      this.position.left = trigger.offsetLeft + trigger.offsetWidth
      this.position.top = trigger.offsetTop + trigger.offsetHeight / 2 - popover.offsetHeight / 2
      break
    case 'bottom':
      this.position.left = trigger.offsetLeft - popover.offsetWidth / 2 + trigger.offsetWidth / 2
      this.position.top = trigger.offsetTop + trigger.offsetHeight
      break
    default:
      console.warn('Wrong placement prop')
  }
  popover.style.top = this.position.top + 'px'
  popover.style.left = this.position.left + 'px'
});