I've created a directive but I can't get it to work with a "executed" handler: Here is how the directive is created:
vueApp.directive('click-outside', {
beforeMount(el, binding, vnode) {
el.clickOutsideEvent = (evt) => {
evt.stopPropagation();
if (!(el === evt.target || el.contains(evt.target))) {
binding.value(evt, el);
}
}
// Wait 1 frame otherwise a potential click that mounted the element will immediately trigger a click-outside event:
window.requestAnimationFrame(() => { document.addEventListener('click', el.clickOutsideEvent) });
},
unmounted(el) {
document.removeEventListener('click', el.clickOutsideEvent);
},
});
If I add a handler like for example close
will work (the close function will be called):
<div v-if="opened" v-click-outside="close">
Some content
</div>
But if I use a bit of script it fails:
<div v-if="opened" v-click-outside="opend = false">
Some content
</div>
or
<div v-if="opened" v-click-outside="close()">
Some content
</div>
These give me an error: Uncaught TypeError: binding.value is not a function
This behavior works for e.g. a @click directive @click="opened = !opened"
or @click="open()"
So the question is if and how can I change the directive so it works in all cases.
CodePudding user response:
Unlike v-bind
, the binding value of your directive is evaluated immediately upon rendering the template. @vue/compiler-sfc
transforms expressions in the v-bind
value into a function, but you have to manually do that for your custom directive:
<div v-if="opened" v-click-outside="() => opened = false">
Some content