如何检测在其他文件中定义的函数是否存在?
我编写了一个处理拖拽功能的库,里面定义了若干CustomEvent,打算在多个Vue3项目中复用。每个项目可能会定义或不定义这些事件的处理函数。
我用以下代码检测处理函数是否存在:
if (typeof onDropped === 'function') { const event = new CustomEvent("dropped", { detail: this.el.id }); this.el.addEventListener( "dropped", onDropped(event), false ); this.el.dispatchEvent(event); }
当onDropped函数和检测代码在同一文件时,一切正常:
var onDropped = function(e) { console.log(e.type + ' handled; data: ' + e.detail) }
如果没定义这个函数也不会出问题,事件不会被创建。但当onDropped定义在使用该库的其他文件中时,库就检测不到它了。
我试过用import/export的方式,但函数未定义时这种方式无法生效,而且库也不知道该从哪里导入。我还试过用if (window.onDropped)替代if (typeof onDropped === 'function'),同样没成功。
我做了一个示例,展示当处理函数在同一文件时CustomEvent的创建和使用正常,但没法复现处理函数在其他文件时检测失败的场景。
*所有项目均使用Vue3.js,但不确定这是否和解决方案相关。
解决方案
1. 让库接受外部传入的处理函数
最直接的方式是修改库的设计,允许使用库的项目主动传入事件处理函数,而非让库在作用域中被动查找。比如给库的初始化方法添加配置参数:
// 拖拽库代码 class DragLibrary { constructor(options = {}) { // 接收外部传入的处理函数 this.handlers = { onDropped: options.onDropped || null }; this.el = // 你的元素获取逻辑 } triggerDropped() { if (typeof this.handlers.onDropped === 'function') { const event = new CustomEvent("dropped", { detail: this.el.id }); // 注意:addEventListener需传入函数引用,而非执行结果 this.el.addEventListener("dropped", this.handlers.onDropped, false); this.el.dispatchEvent(event); // 可选:一次性事件触发后移除监听 this.el.removeEventListener("dropped", this.handlers.onDropped); } } } // 项目中使用 import DragLibrary from './drag-library'; const onDropped = (e) => { console.log(e.type + ' handled; data: ' + e.detail); }; const dragLib = new DragLibrary({ onDropped }); // 触发事件时调用对应方法 dragLib.triggerDropped();
2. 利用Vue全局事件总线(适配Vue3项目)
在Vue3中可以自己实现简易全局事件总线,或使用官方推荐的mitt库,让库与项目通过总线传递事件:
// 拖拽库中引入事件总线 import mitt from 'mitt'; const emitter = mitt(); class DragLibrary { constructor() { this.el = // 你的元素获取逻辑 } triggerDropped() { const event = new CustomEvent("dropped", { detail: this.el.id }); this.el.dispatchEvent(event); // 同时通过总线分发事件 emitter.emit('dropped', event.detail); } } // 项目中使用 import { emitter } from './drag-library'; // 注册事件监听 const onDropped = (data) => { console.log('dropped handled; data: ' + data); }; emitter.on('dropped', onDropped); // 不需要时移除监听 // emitter.off('dropped', onDropped);
3. 修复原代码的监听逻辑错误
你原代码存在一个关键问题:addEventListener的第二个参数传的是onDropped(event),这会立即执行函数并将返回值(无返回则为undefined)传给监听,正确写法是传入函数引用,或用箭头函数包裹:
// 错误写法 this.el.addEventListener("dropped", onDropped(event), false); // 正确写法1:直接传函数引用 this.el.addEventListener("dropped", onDropped, false); // 正确写法2:需传额外参数时用箭头函数包裹 this.el.addEventListener("dropped", (e) => onDropped(e, extraData), false);
4. 挂载到全局对象(不推荐)
如果一定要用全局变量方式,需确保处理函数确实挂载到window上。Vue3组件中定义的函数需要显式赋值给全局对象:
// 项目组件中 window.onDropped = function(e) { console.log(e.type + ' handled; data: ' + e.detail); }; // 库中检测 if (typeof window.onDropped === 'function') { // 后续逻辑需注意监听的正确写法 }
这种方式会污染全局作用域,容易引发命名冲突,不推荐使用。
内容的提问来源于stack exchange,提问作者quilkin

