Vue.js 自定义指令使用 TypeScript 检测点击外部元素

Posted

技术标签:

【中文标题】Vue.js 自定义指令使用 TypeScript 检测点击外部元素【英文标题】:Vue.js custom directive detecting click outside element with TypeScript 【发布时间】:2020-08-27 01:42:24 【问题描述】:

我正在尝试使用此示例创建自定义指令:https://***.com/a/42389266/5470563

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
        
);

我得到一个编译错误:

htmlElement”类型上不存在属性“clickOutsideEvent”。

我该如何解决?或者有没有更好的解决方案来绑定外部元素点击事件?

【问题讨论】:

【参考方案1】:

你有两个选择

bindunbind 函数中的el 参数转换为any

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

扩展HTMLElement接口。

你可以把它放在指令声明之前。

interface HTMLElement 
  clickOutsideEvent: () => void;

【讨论】:

编译现在运行良好,但单击任意位置后出现 JS 错误:Uncaught TypeError: vnode.context[binding.expression] is not a function at HTMLBodyElement.el.clickOutsideEvent 哦,这是因为我没有将函数定义为 v-click-outside 自定义指令的属性。谢谢!【参考方案2】:

这是我目前使用的一个实现,希望对您有所帮助:

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;
  
;

然后在你的主文件中注册指令

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

【讨论】:

OP 有打字稿错误,他的 javascript 代码看起来不错。 只是建议我以前使用的解决方案,以防万一这个解决方案不起作用。

以上是关于Vue.js 自定义指令使用 TypeScript 检测点击外部元素的主要内容,如果未能解决你的问题,请参考以下文章

03Vue.js---自定义指令

vue.js自定义指令入门

Vue.js 自定义指令

Vue.js 中的自定义指令

Vue.js 源码分析(二十三) 高级应用 自定义指令详解

Vue.js学习 Item13 – 指令系统与自定义指令