当前位置: 首页 > 知识库问答 >
问题:

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

百里承业
2024-12-12

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所触发,要怎么写。

共有2个答案

徐昆
2024-12-12

通过 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 实例,从而避免了事件监听器在全局范围内触发的问题。

吕树
2024-12-12

回答

在 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` 组件实例都会独立管理自己的事件监听器,不会受到其他组件实例的影响,从而解决了重复执行的问题。
 类似资料:
  • 下面的代码直接打开这个页面执行没有问题,但是做为组件放到Dialog里被另一个页面执行,打开是图片就无放显示,有大神能看出是哪里问题吗?

  • vue3.0+tsx中子组件注册的两个emit方法,点击事件btnclick在父组件中正常,然后一个接收消息的事件rollback,没触发。 子组件: 接收socket消息是正常的,msg也能正常打印,就是父组件无法接收事件 父组件: 父组件没触发rollback方法,有没有大神帮忙看下怎么回事

  • 问题内容: 我在一个商业android应用程序上工作。我还使用了一些使用不同许可类型许可的库,其中一些声明如下: 如果库中有带有归因说明的“ NOTICE”文件,则在分发时必须包括该NOTICE (例如,其中之一已获得 Apache License 2.0 的 许可 )。 有多个库。使用 gradle 或 Android Studio 进行构建时,出现以下构建错误: 到目前为止,我在Interne

  • 我在一个商业android应用程序工作。我还使用了一些在不同许可类型下许可的库,其中一些声明如下: (例如,其中一个是在Apache License2.0下获得许可的)。 不止一个图书馆。当我使用gradle或Android Studio进行构建时,我会得到以下构建错误: 到目前为止,我在internet和stackoverflow上找到的答案建议,通过在文件中添加以下内容,从打包中删除licen

  • 我在一个商业android应用程序上工作。我还在使用一些根据不同许可证类型授权的库,其中一些声明如下: 如果库中有一个带有属性注释的“通知”文件,则在分发时必须包含该通知 (例如,其中一个是Apache License 2.0许可的)。 图书馆不止一个。当我使用gradle或Android Studio进行构建时,我得到以下构建错误: 根据这些库的许可证(例如Apache许可证2.0),应该包括许

  • 我正在中绑定组件 当我试图从访问时 最后是 错误[org.apache.catalina.core.containerbase.[jboss.web].[default-host].[/mdf-portal-web].[Faces Servlet]](http-localhost-127.0.0.1-8080-10)Servlet Faces Servlet的Servlet.service()引发

  • 主要内容:全局组件实例,实例,实例,全局组件实例,局部组件实例,Prop,Prop 实例,Prop 实例组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树: 每个 Vue 应用都是通过用 createApp 函数创建的,传递给 createApp 的选项用于配置根组件。当我们挂载应用时,该组件被用作渲染的起点。 一个应用需要被挂载到一

  • 使用vue3开发项目,其中有使用iframe内嵌外部链接页面(外部链接不是自己的项目),打包成静态页面。 先在项目外打开并登录该内嵌页面 再从项目中打开该内嵌页面会发现该内嵌页面的登录状态失效了 且只有IOS会这样,Android不会 我是直接通过js操作Iframe替换的src的链接 根据搜索来的方法尝试过 但仍然没有效果,最后只好把IOS先禁用掉