Home > Blockchain >  Custom directive to replace @mouseenter @mouseleave event?
Custom directive to replace @mouseenter @mouseleave event?

Time:07-05

I'm having lots of elements on which @mouseenter set a value to true and @mouseleave sets it to false. Basically what I need is a way to set a reactive variable to true if the mouse hovers the element.

I've been trying to figure out how to write such custom directive from the docs but it only mentions how to use .focus() js function on an element. Which js functions would be used for said directive?

Something like:

const vHover = {
    mounted: (el) => {
        el.addEventListener('mouseenter', state.hover=true)
        el.addEventListener('mouseleave', state.hover=false)
    }
}

CodePudding user response:

I think you could do something like:

app.directive('hover', {
    created(el, binding) {
        const callback = binding.value
        el.onmouseenter = () => callback(true)
        el.onmouseleave = () => callback(false)
    },
    unmounted(el) {
        el.onmouseenter = null
        el.onmouseleave = null
    }
})

Template:

<button v-hover="onHoverChange">Example</button>

Methods:

onHoverChange(isHovered) {
    console.log(isHovered)
}

CodePudding user response:

I believe this is not the intended use of directives. The value of the state cannot be mutated within the directive. You can pass the variable through the binding, but you cannot update it.

binding: an object containing the following properties.

  • value: The value passed to the directive. For example in v-my-directive="1 1", the value would be 2.
  • oldValue: The previous value, only available in beforeUpdate and updated. It is available whether or not the value has changed.

so if you do el.addEventListener('mouseenter', binding.hover=true), as you may have noticed, it will not update the state.

However, if we use the internals (PSA: though not recommended since they could potentially change at any time), you could get instance using the vnode, and use the binding.arg to denote which Proxy (state)

so you could get the reactive variable with vnode.el.__vueParentComponent.data[binding.arg]

<script>
export default {
  data(){
    return {
      state: { hover:false }
    }
  },
  directives: {
    hover: {
      mounted(el, binding, vnode) {
        el.addEventListener('mouseenter', () => {
          vnode.el.__vueParentComponent.data[binding.arg].hover = true
        })
        el.addEventListener('mouseleave', () => {
          vnode.el.__vueParentComponent.data[binding.arg].hover = false
        })
      },
    }
  }
}
</script>

<template>
  <h1 v-hover:state="state">HOVER {{ state }}</h1>
</template>

SFC playground link

of course you might want to add the unmounted and even consider adding mouseleave dynamically only when mouseenter fires

  • Related