在 Vue 3 中,组件之间传递数据有多种方式

阅读 16

03-09 21:00

1. 父组件向子组件传值:props

props 是父组件向子组件传递数据的主要方式。

示例代码

<!-- 父组件 Parent.vue -->
<template>
  <div>
    <Child :message="parentMessage" />
  </div>
</template>

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

const parentMessage = ref('Hello from parent');
</script>

<!-- 子组件 Child.vue -->
<template>
  <div>
    {{ message }}
  </div>
</template>

<script setup>
const props = defineProps({
  message: String
});
</script>

解析

  • 父组件:在父组件中,通过在子组件标签上使用 :(即 v-bind 的缩写)绑定一个数据属性,将 parentMessage 传递给子组件。
  • 子组件:在子组件中,使用 defineProps 宏来定义接收的 propsdefineProps 接收一个对象,对象的键是 props 的名称,值是该 props 的类型。子组件可以在模板中直接使用接收到的 props

2. 子组件向父组件传值:emits 和自定义事件

子组件通过触发自定义事件向父组件传递数据。

示例代码

<!-- 父组件 Parent.vue -->
<template>
  <div>
    <Child @childEvent="handleChildEvent" />
    <p>Received from child: {{ receivedMessage }}</p>
  </div>
</template>

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

const receivedMessage = ref('');

const handleChildEvent = (message) => {
  receivedMessage.value = message;
};
</script>

<!-- 子组件 Child.vue -->
<template>
  <button @click="sendMessage">Send message to parent</button>
</template>

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

const emits = defineEmits(['childEvent']);

const sendMessage = () => {
  emits('childEvent', 'Hello from child');
};
</script>

解析

  • 子组件:使用 defineEmits 宏定义可以触发的自定义事件。在子组件的方法中,通过 emits 函数触发自定义事件,并传递数据。
  • 父组件:在父组件中,使用 @(即 v-on 的缩写)监听子组件的自定义事件,并定义一个方法来处理该事件。当子组件触发事件时,父组件的处理方法会被调用,并接收子组件传递的数据。

3. 兄弟组件传值:事件总线或状态管理库

事件总线

事件总线是一个简单的全局事件系统,用于组件之间的通信。

示例代码

// eventBus.js
import { ref, reactive } from 'vue';

const eventBus = reactive({
  events: {},
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  },
  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach((callback) => callback(data));
    }
  },
  off(event, callback) {
    if (this.events[event]) {
      const index = this.events[event].indexOf(callback);
      if (index !== -1) {
        this.events[event].splice(index, 1);
      }
    }
  },
});

export default eventBus;
<!-- 组件 A.vue -->
<template>
  <button @click="sendMessage">Send message to sibling</button>
</template>

<script setup>
import eventBus from './eventBus.js';

const sendMessage = () => {
  eventBus.emit('siblingEvent', 'Hello from sibling A');
};
</script>

<!-- 组件 B.vue -->
<template>
  <p>Received from sibling: {{ receivedMessage }}</p>
</template>

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

const receivedMessage = ref('');

const handleSiblingEvent = (message) => {
  receivedMessage.value = message;
};

eventBus.on('siblingEvent', handleSiblingEvent);
</script>

解析

  • 事件总线:创建一个全局的事件总线对象,包含 onemitoff 方法,分别用于监听事件、触发事件和取消监听事件。
  • 组件通信:一个组件通过 emit 方法触发事件并传递数据,另一个组件通过 on 方法监听该事件,并在回调函数中处理接收到的数据。

状态管理库(以 Pinia 为例)

Pinia 是 Vue 3 推荐的状态管理库,用于在多个组件之间共享状态。

示例代码

// stores/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++;
    }
  }
});
<!-- 组件 A.vue -->
<template>
  <button @click="increment">Increment</button>
</template>

<script setup>
import { useCounterStore } from '../stores/counter';

const counterStore = useCounterStore();
const increment = () => {
  counterStore.increment();
};
</script>

<!-- 组件 B.vue -->
<template>
  <p>Count: {{ counterStore.count }}</p>
</template>

<script setup>
import { useCounterStore } from '../stores/counter';

const counterStore = useCounterStore();
</script>

解析

  • 状态管理:使用 defineStore 定义一个 store,包含状态和操作状态的方法。
  • 组件使用:多个组件可以通过 useCounterStore 函数获取同一个 store 实例,从而共享状态和调用操作状态的方法。

4. 跨层级组件传值:provideinject

provideinject 用于在跨层级的组件之间传递数据。

示例代码

<!-- 祖先组件 Ancestor.vue -->
<template>
  <div>
    <Descendant />
  </div>
</template>

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

const sharedData = ref('Shared data from ancestor');
provide('sharedData', sharedData);
</script>

<!-- 后代组件 Descendant.vue -->
<template>
  <div>
    {{ injectedData }}
  </div>
</template>

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

const injectedData = inject('sharedData');
</script>

解析

  • 祖先组件:使用 provide 函数提供一个数据,第一个参数是提供的数据的键,第二个参数是要提供的数据。
  • 后代组件:使用 inject 函数注入祖先组件提供的数据,参数是要注入的数据的键。后代组件可以直接使用注入的数据。

精彩评论(0)

0 0 举报