Home > Software design >  Vue 3 directive handler not working as basic directives
Vue 3 directive handler not working as basic directives

Time:11-12

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                               
  • Related