Búsqueda de sitios web

Directiva personalizada de Vue.js que detecta clic fuera del elemento con TypeScript


Estoy tratando de crear una directiva personalizada usando este ejemplo: https://stackoverflow.com/a/42389266/5470563

archivo main.ts:

import Vue from 'vue';
import HeaderNav from './components/HeaderNav.vue'

Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
        el.clickOutsideEvent = function (event) {
            // here I check that click was outside the el and his childrens
            if (!(el == event.target || el.contains(event.target))) {
                // and if it did, call method provided in attribute value
                vnode.context[binding.expression](event);
            }
        };
        document.body.addEventListener('click', el.clickOutsideEvent)
    },
    unbind: function (el) {
        document.body.removeEventListener('click', el.clickOutsideEvent)
    },
});

new Vue({
    el: '#app',
        components: {
            HeaderNav
        }
});

Y obtengo un error de compilación:

La propiedad 'clickOutsideEvent' no existe en el tipo 'HTMLElement'.

¿Cómo lo arreglo? ¿O hay alguna mejor solución para vincular eventos al hacer clic fuera del elemento?

Respuesta #1

Tienes 2 opciones

convierte el parámetro el en las funciones bind y unbind a any.

bind: function (el: any, binding, vnode) {
unbind: function (el: any) {

extender la interfaz HTMLElement.

Puedes colocarlo antes de la declaración de la directiva.

interface HTMLElement {
  clickOutsideEvent: () => void;
}

Respuesta #2

Aquí hay una implementación que uso actualmente, espero que ayude:

export default {
  bind: function(el, binding, vNode) {
    // Provided expression must evaluate to a function.
    if (typeof binding.value !== "function") {
      const compName = vNode.context.name;
      let warn = `[Vue-click-outside:] provided expression '${binding.expression}' is not a function, but has to be`;
      if (compName) {
        warn += `Found in component '${compName}'`;
      }

      console.warn(warn);
    }
    // Define Handler and cache it on the element
    const bubble = binding.modifiers.bubble;
    const handler = e => {
      if (bubble || (!el.contains(e.target) && el !== e.target)) {
        binding.value(e);
      }
    };
    el.__vueClickOutside__ = handler;
    // add Event Listeners
    document.addEventListener("mousedown", handler);
  },
  unbind: function(el, binding) {
    // Remove Event Listeners
    document.removeEventListener("mousedown", el.__vueClickOutside__);
    el.__vueClickOutside__ = null;
  }
};

Luego registra la directiva en tu archivo principal

// Directives
Vue.directive("click-outside", ClickOutside);