Vue组件通信(二)

1,352 阅读3分钟

这篇我们来续上上一篇的组件通讯的方法Vue组件通讯(一) - 掘金 (juejin.cn)

provideinject

用于跨组件传递数据。它们可以让父组件为其所有的后代组件提供数据,而不必通过逐层的 props 传递。可以实现祖孙通信。还是来用上一篇的案例来做示例。

// Grandparent.vue
<template>
  <div class="header">
    <input type="text" v-model="newMsg">
    <button @click="add">确定</button>
  </div>
  <Child />
</template>

<script setup>
import { ref, provide } from 'vue';
import Child from './child.vue';

const newMsg = ref('');
const list = ref(['html', 'css']);

const add = () => {
  list.value.push(newMsg.value);
  newMsg.value = ''; 
};

provide('list', list);
</script>
// child.vue
<template>
    <div class="body">
        <ul>
            <li v-for="item in list" :key="item">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
import { inject } from 'vue';

const list = inject('list')
</script>

provide提供用来将 list 提供给其后代组件。这意味着任何后代组件都可以通过 inject 方法来访问这个 list。然后我们就在孙子组件用inject接收到list,用来循环渲染到页面上。

全局事件总线 (任意组件通信)

全局事件总线是一种在 Vue 应用程序中实现任意组件之间通信的方法。这种方法特别适用于那些没有直接父子关系的组件之间的通信,或者需要跨越多个层级进行通信的情况。

但是在Vue3.0中官方已经移除了对全局事件总线的支持,主要是因为全局事件总线可能导致一些维护和调试上的问题。不过还是有一个轻量级的事件总线库mitt,原理还是EventBus

四个步骤

  1. 先安装一下 npm i mitt -save
  2. 创建 mitt 实例
import mitt from 'mitt';
const eventBus = mitt();
export default eventBus;
  1. 发送事件
<template>
  <div class="header">
    <input type="text" v-model="newMsg">
    <button @click="add">确定</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import eventBus from './mitt';

const newMsg = ref('');
const list = ref([]);

const add = () => {
  if (newMsg.value) {
    list.value.push(newMsg.value);
    newMsg.value = '';
    // 触发事件,通知子组件更新
    eventBus.emit('list-updated', list.value);
  }
};
</script>
  1. 监听事件
<template>
  <div class="body">
    <ul>
      <li v-for="item in list" :key="item">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import eventBus from './mitt';

const list = ref([]);

// 监听事件
const updateList = (newList) => {
  list.value = newList;
};

onMounted(() => {
  eventBus.on('list-updated', updateList);
});

onBeforeUnmount(() => {
  // 移除监听器
  eventBus.off('list-updated', updateList);
});
</script>

不过有一说一使用这种方法还是有点麻烦不太推荐。

状态管理库

前面也简单介绍过Pinia和Vuex

你知道的状态管理库Pinia - 掘金 (juejin.cn)

你知道的状态管理库Vuex - 掘金 (juejin.cn)

感兴趣可以去简单了解一下这里就直接使用一下来完成这个demo

Pinia

创建状态库

import { defineStore } from 'pinia';

export const useListStore = defineStore('listStore', {
  state: () => ({
    list: []
  }),
  actions: {
    addItem(item) {
      if (item.trim() !== '') {
        this.list.push(item.trim());
      }
    },
    setList(newList) {
      this.list = newList;
    }
  }
});

一个组件输入内容

<template>
    <div class="header">
        <input type="text" v-model="newMsg">
        <button @click="add">确定</button>
    </div>
</template>

<script setup>
import { ref } from 'vue';
import { useListStore } from '../../store/pinia';

const newMsg = ref('');
const listStore = useListStore();

const add = () => {
    listStore.addItem(newMsg.value);
    newMsg.value = '';
};
</script>

一个渲染数据

<template>
    <div class="body">
        <ul>
            <li v-for="item in list" :key="item">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
import { useListStore } from '../../store/pinia';

const listStore = useListStore();
const list = listStore.list;
</script>

Vuex与Pinia的方式思想大差不差就是两种的使用方法有些不同这里也就不再过多去使用了感兴趣的可以自己去尝试一下。

结尾

通过本文的讲解,你应该对 Vue 组件通信的多种方法有了更深入的了解。从传统的 propsemits,到更高级的 provideinject,再到全局事件总线和状态管理库(如 Pinia 和 Vuex),每种方法都有其特定的适用场景。选择适合的通信方式可以帮助你更有效地管理 Vue 应用中的数据流和组件交互。如果你对某种方法感兴趣,可以进一步探索和实践,以便更好地应用到你的项目中。

继续学习和探索吧,掌握这些技能会让你的 Vue 开发更加高效和灵活!