Vue中事件发射器注销与GISWSCaller类封装及调用问询
问题解答
一、当前unregisterEvtEmitter写法是否正确?事件发射器的正确注销方式
当前写法完全不正确,你只是把计算属性的值设为undefined,根本没有实现事件发射器的注销逻辑。
首先明确核心逻辑:你当前用的是Vue组件的defineEmits定义的组件事件,这类事件的监听由父组件完成,子组件仅负责触发(emit)。针对"注销"需求,分两种场景处理:
1. 父组件取消监听子组件事件
父组件可通过动态绑定v-on或组件实例的$off方法(Vue2)取消监听;Vue3 <script setup>中,需通过ref获取子组件实例后调用对应方法。
2. 子组件内部清理事件相关资源
如果需求是子组件停止触发事件、清理异步请求或状态,正确做法是:
- 取消正在进行的异步请求(用
AbortController) - 清理存储的参数和结果状态
修正后的示例代码:
// 新增请求控制器用于取消异步请求 const abortController = ref(null); // 修改事件触发逻辑,加入请求取消机制 const emit = defineEmits({ evtRunWSRouteTest: async (params) => { // 先取消未完成的请求 if (abortController.value) abortController.value.abort(); abortController.value = new AbortController(); const splitted = params.split(','); if (splitted.length === 4) { try { const response = await fetch(`https://xx/xx/getDistanceFromOriginToDestination/${params}`, { signal: abortController.value.signal }); res.value = await response.json(); return res.value; } catch (err) { // 忽略请求取消的报错 if (err.name !== 'AbortError') { console.error('请求失败', err); return false; } } } return false; } }); // 正确的注销函数 function unregisterEvtEmitter() { // 取消请求 if (abortController.value) abortController.value.abort(); // 清理状态 params = null; res.value = null; }
如果是使用自定义事件发射器(如Node.js events模块或第三方库mitt),注销需调用发射器的off方法移除对应监听:
// 示例:用mitt实现自定义事件发射器 import mitt from 'mitt'; const emitter = mitt(); // 监听事件 emitter.on('evtRunWSRouteTest', handler); // 注销事件监听 function unregisterEvtEmitter() { emitter.off('evtRunWSRouteTest', handler); // 或清空所有监听 // emitter.all.clear(); }
二、封装为GISWSCaller类并导出,Vue文件中的调用方式
1. 封装GISWSCaller类
创建GISWSCaller.js文件:
import { ref, computed } from 'vue'; export class GISWSCaller { constructor() { this.res = ref(null); this.params = ref(null); this.abortController = null; // 若需自定义事件发射器,可引入mitt // import mitt from 'mitt'; // this.emitter = mitt(); } // 计算属性,用于触发请求 get evtEmitterParamsCompProperties() { return computed({ get: () => this.params.value, set: (newValue) => this.runRouteTest(newValue) }); } // 执行路由测试请求 async runRouteTest(params) { // 取消之前的请求 if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); this.params.value = params; const splitted = params.split(','); if (splitted.length === 4) { try { const response = await fetch(`https://xx/xx/getDistanceFromOriginToDestination/${params}`, { signal: this.abortController.signal }); this.res.value = await response.json(); // 若用自定义事件发射器,触发事件 // this.emitter.emit('evtRunWSRouteTest', this.res.value); return this.res.value; } catch (err) { if (err.name !== 'AbortError') { console.error('请求失败', err); return false; } } } return false; } // 注销/清理资源 unregisterEvtEmitter() { // 取消请求 if (this.abortController) this.abortController.abort(); // 清理状态 this.params.value = null; this.res.value = null; // 若用自定义事件发射器,清空监听 // this.emitter.all.clear(); } }
2. 在Vue组件中调用类实例
修改Vue组件代码:
<template> <div class="container"> <button @click="handleRouteTest">routTest</button> result:{{ caller.res }} </div> </template> <script setup> import { GISWSCaller } from './GISWSCaller.js'; import { onUnmounted } from 'vue'; // 创建类实例 const caller = new GISWSCaller(); // 触发路由测试 function handleRouteTest() { const param = '30.976639,30.056021,30.97775,30.033333'; // 方式1:直接调用请求方法 caller.runRouteTest(param); // 方式2:通过计算属性设置值触发请求 // caller.evtEmitterParamsCompProperties.value = param; } // 组件卸载时自动清理资源 onUnmounted(() => { caller.unregisterEvtEmitter(); }); </script>
补充说明
- 封装类后,所有状态和方法都聚合在类内部,更易于复用和维护;
- 若使用自定义事件发射器,Vue组件可通过类实例的
emitter.on监听事件,emitter.off取消监听。
内容的提问来源于stack exchange,提问作者Amrmsmb
相关产品推荐
相关产品推荐

