如何在VUE3中解决mitt事件在复用组件中重复执行的问题?

VUE3中 在复用组件中使用mitt,重复执行
childA

<script lang="ts" setup>
const handleFunc = () => {
     mitter.emit('on-func')
}
</script>

childB

<script lang="ts" setup>
const count = ref<number>(0)
onMounted(() => {
    mitter.on('on-func')
    count.value++
    console.log('count', count.value)
})
</script>

父组件--parent

<template>
   <childA />
   <childB />
</template>

在页面中复用父组件

<template>
   <parent />
  <parent />
  <parent />
</template>

上述代码中,当触发三个<parent />组件其中之一的时候,<childB />中的 mitter.on('on-func')会被触发三次。
复用组件的时候,mitt会存在组件隔离吗,如果mitter.on只想被当前组件的mitter.emit所触发,要怎么写。

阅读 736
avatarAI BotBETA

回答

在 Vue 3 中使用 mitt 进行事件管理时,如果在复用组件中遇到事件重复执行的问题,通常是因为事件监听器 (mitter.on) 没有在组件卸载时正确移除。这会导致每当组件重新挂载时,都会添加一个新的监听器,而旧的监听器依然存在,从而引发重复执行的问题。

为了解决这个问题,你应该在 onUnmounted 钩子中移除之前添加的监听器。这样可以确保每个组件实例只会有一个监听器,并且在组件销毁时清理掉。

以下是修改后的 childB 组件代码:

<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue';
import mitter from 'mitt'; // 确保你已经正确导入了 mitt 实例

const count = ref<number>(0);

const handleFunc = () => {

count.value++;
console.log('count', count.value);

};

onMounted(() => {

mitter.on('on-func', handleFunc);

});

onUnmounted(() => {

mitter.off('on-func', handleFunc);

});
</script>


在这个修改中,我们定义了一个 `handleFunc` 函数来处理事件,并在 `onMounted` 钩子中将其添加到 mitt 的事件监听器中。同时,在 `onUnmounted` 钩子中,我们使用 `mitter.off` 来移除这个监听器。

这样,每个 `childB` 组件实例都会独立管理自己的事件监听器,不会受到其他组件实例的影响,从而解决了重复执行的问题。
1 个回答

通过 mitt 独立实例避免事件监听器在全局范围内触发的问题

创建一个 mitt 实例工厂

utils 文件夹中创建一个 mittFactory.ts 文件,用于生成 mitt 实例:

// utils/mittFactory.ts
import mitt from 'mitt';

export const createMitt = () => {
  return mitt();
};

在组件中使用独立的 mitt 实例

在每个组件中引入并使用这个工厂函数来创建 mitt 实例。

childA.vue
<script lang="ts" setup>
import { createMitt } from '../utils/mittFactory';

const mitter = createMitt();

const handleFunc = () => {
  mitter.emit('on-func');
};
</script>
childB.vue
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { createMitt } from '../utils/mittFactory';

const mitter = createMitt();
const count = ref<number>(0);

onMounted(() => {
  mitter.on('on-func', () => {
    count.value++;
    console.log('count', count.value);
  });
});
</script>

在父组件中传递 mitt 实例

在父组件中创建 mitt 实例并通过 props 传递给子组件。

parent.vue
<template>
  <childA :mitter="mitter" />
  <childB :mitter="mitter" />
</template>

<script lang="ts" setup>
import { createMitt } from '../utils/mittFactory';
import ChildA from './ChildA.vue';
import ChildB from './ChildB.vue';

const mitter = createMitt();
</script>

在子组件中接收 mitt 实例

修改子组件以接收并使用传递的 mitt 实例。

childA.vue
<script lang="ts" setup>
import { defineProps } from 'vue';

const props = defineProps<{ mitter: any }>();

const handleFunc = () => {
  props.mitter.emit('on-func');
};
</script>
childB.vue
<script lang="ts" setup>
import { ref, onMounted, defineProps } from 'vue';

const props = defineProps<{ mitter: any }>();
const count = ref<number>(0);

onMounted(() => {
  props.mitter.on('on-func', () => {
    count.value++;
    console.log('count', count.value);
  });
});
</script>

通样每个父组件实例都会有自己的 mitt 实例,从而避免了事件监听器在全局范围内触发的问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏