javascriptvuejs3vue-directives

Vuejs3.0 how to make directive to detect if user clicked outside of the component?


I have question how to rewrite vue2.0 custom directive to work with vuejs3.0? The directive purpose is detect if user clicked or not outside of the component.

Okey. here is code what worked on vuejs2.X.X but now is not working. Reasons later.

import { DirectiveOptions } from 'vue';

export default {
  bind: (el: any, binding, vnode) => {
    el.clickOutsideEvent = (event: any) => {
      const clickedOutsideTargetAndChildren = !(el == event.target || el.contains(event.target!));
      const targetInDOM = document.body.contains(event.target);
      const bodyIsFocused = document.activeElement === document.body;

      if (clickedOutsideTargetAndChildren && targetInDOM && bodyIsFocused && vnode.context) {
        const vueContext = vnode.context as any;
        vueContext[binding.expression!](event);
      }
    };
    document.body.addEventListener('click', el.clickOutsideEvent)
  },
  unbind: (el: any) => {
    document.body.removeEventListener('click', el.clickOutsideEvent)
  },
} as DirectiveOptions

I found [click][1] what in vuejs3.X some hooks changed their names [hooks name changes from vue2 to vue3][2] also what node.context is undefined and need to use binding.value instead [Founded it here][3]

Some my raw version on directive to detect if user clicked outside component is

 clickOutside: { 
                beforeMount : (el: any, binding: any, vnode: any) => {
                    el.clickOutsideEvent = (event: any) => {
                        const clickedOutsideTargetAndChildren = !(el === event.target || el.contains(event.target!));
                        const targetInDOM = document.body.contains(event.target);
                        const bodyIsFocused = document.activeElement === document.body;
                        console.log(vnode.context);//undefined
                        console.log('binding.instance',binding.instance);//returns vue instance
                        if (clickedOutsideTargetAndChildren && targetInDOM && bodyIsFocused && vnode.context) {
                            const vueContext = vnode.context as any;
                            vueContext[binding.expression!](event);// what is this???
                        }
                    };
                    document.body.addEventListener('click', el.clickOutsideEvent)
                },

                unmounted : (el: any) => {
                    document.body.removeEventListener('click', el.clickOutsideEvent)
                }
}

So question is . How to rewrite vuejs2.0 directive to work with vuejs3.0? P.S Would be nice not using composition API. [1]: Custom directives in Vue 3 [2]: https://i.sstatic.net/9k8MO.png [3]: https://iditect.com/guide/vuejs3/vuejs3-8s2f3f3g.html


Solution

    1. Add an click event listener to window object in the onMounted lifecycle hook (and remove it in onBeforeDestroy)
    2. In the handler for this event check if a DOM node you wish is included in the composedPath of the mouse event

    Detailed tutorial here: https://www.youtube.com/watch?v=tevotcV6D2E