在 Vue 中移除多個(gè)事件監(jiān)聽器,核心思路是 “集中管理事件與回調(diào)的關(guān)聯(lián)關(guān)系,在合適時(shí)機(jī)批量遍歷移除”,避免遺漏或重復(fù)操作。以下是具體實(shí)現(xiàn)方法,覆蓋 Vue 3 和 Vue 2 場景:
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
const btnRef = ref(null);
const events = [
{ type: 'click', handler: handleClick },
{ type: 'mouseenter', handler: handleMouseEnter }
];
function handleClick() { /* ... */ }
function handleMouseEnter() { /* ... */ }
onMounted(() => {
events.forEach(({ type, handler }) => {
btnRef.value?.addEventListener(type, handler);
});
});
onUnmounted(() => {
events.forEach(({ type, handler }) => {
btnRef.value?.removeEventListener(type, handler);
});
});
</script>
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
const boxRef = ref(null);
const eventMap = new Map([
['mousedown', handleMouseDown],
['mousemove', handleMouseMove],
['mouseup', handleMouseUp]
]);
function handleMouseDown() { /* ... */ }
function handleMouseMove() { /* ... */ }
function handleMouseUp() { /* ... */ }
onMounted(() => {
eventMap.forEach((handler, type) => {
boxRef.value?.addEventListener(type, handler);
});
});
onUnmounted(() => {
eventMap.forEach((handler, type) => {
boxRef.value?.removeEventListener(type, handler);
});
});
</script>
export default {
data() {
return {
eventListeners: [
{ el: 'window', type: 'scroll', handler: this.handleScroll },
{ el: 'document', type: 'click', handler: this.handleClick }
]
};
},
methods: {
handleScroll() { },
handleClick() { }
},
mounted() {
this.eventListeners.forEach(({ el, type, handler }) => {
const target = el === 'window' ? window : document;
target.addEventListener(type, handler);
});
},
beforeDestroy() {
this.eventListeners.forEach(({ el, type, handler }) => {
const target = el === 'window' ? window : document;
target.removeEventListener(type, handler);
});
}
};
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import * as echarts from 'echarts';
const chartRef = ref(null);
let chart = null;
// ECharts 事件映射
const chartEvents = [
['click', handleChartClick],
['legendselectchanged', handleLegendChange]
];
function handleChartClick() { /* ... */ }
function handleLegendChange() { /* ... */ }
onMounted(() => {
chart = echarts.init(chartRef.value);
chartEvents.forEach(([type, handler]) => {
chart.on(type, handler);
});
});
onUnmounted(() => {
chartEvents.forEach(([type, handler]) => {
chart.off(type, handler);
});
chart.dispose();
});
</script>
-
確;卣{(diào)函數(shù)引用一致
- 錯(cuò)誤:用匿名函數(shù)綁定
- 正確:用具名函數(shù)或
useCallback 緩存
-
捕獲階段參數(shù)匹配
el.addEventListener('click', handler, true);
el.removeEventListener('click', handler, true);
-
動(dòng)態(tài)元素的事件委托
對 v-for 列表,優(yōu)先用事件委托減少監(jiān)聽:
<ul @click="handleItemClick">
<li v-for="item in list" :data-id="item.id">{{ item.name }}</li>
</ul>
- 管理方式:用數(shù)組 / Map 存儲事件配置,集中管理
- 移除時(shí)機(jī):Vue 3 在
onUnmounted,Vue 2 在 beforeDestroy
- 核心原則:綁定與移除的參數(shù)(類型、回調(diào)、捕獲階段)必須完全一致
|