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>
of course you might want to add the unmounted
and even consider adding mouseleave
dynamically only when mouseenter
fires