本文作者系360奇舞团前端开发工程师

在 Vue 3 中,组件之间的传值是核心操作之一,能够有效组织和共享数据。随着 Vue 3 的引入,除了传统的 Options API,Composition API 也得到了更多应用场景,带来了更多灵活性。本文将深入探讨 Vue 3 中的常见传值方式,详细介绍如何通过 propsemitprovide/inject、以及状态管理工具等实现父子组件、跨级组件甚至全局状态的传递和共享。

1. 父子组件传值

父子组件的传值是 Vue 应用中最常见的场景。父组件通常向子组件传递数据,子组件则可能向父组件反馈事件或传递更新。

1.1 父组件向子组件传值(Props)

在 Vue 中,props 是父组件向子组件传递数据的主要手段。父组件通过模板中绑定的属性向子组件传值,而子组件需要通过声明 props 来接收这些值。

父组件代码

<template>
  <ChildComponent :message="parentMessage" :count="5" />
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
const parentMessage = "Hello from Parent!";
</script>

在这个例子中,父组件将 parentMessage 和数值 5 作为 props 传递给子组件。

子组件代码

<template>
  <div>
    <p>{{ message }}</p>
    <p>{{ count }}</p>
  </div>
</template>

<script setup>
defineProps({
  message: String,  // message 要求为字符串
  count: Number     // count 要求为数字
});
</script>

defineProps 是 Composition API 中的一个新函数,用于声明组件需要接收的 props。这使得子组件可以直接使用父组件传入的数据。

1.2 子组件向父组件传值(emit)

子组件可以通过 emit 方法向父组件发送事件,通常用于通知父组件某些用户交互的结果。emit 还可以附带数据,以便父组件根据接收到的事件执行相应操作。

子组件代码

<template>
  <button @click="sendMessageToParent">Send Message</button>
</template>

<script setup>
const emit = defineEmits(['sendMessage']);

function sendMessageToParent() {
  emit('sendMessage', 'Hello from Child');
}
</script>

子组件通过 defineEmits 声明它可能发出的事件,然后在点击按钮时使用 emit 函数向父组件发送 sendMessage 事件,并附带一条消息。

父组件代码

<template>
  <ChildComponent @sendMessage="handleMessage" />
  <p>{{ receivedMessage }}</p>
</template>

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

const receivedMessage = ref('');

function handleMessage(message) {
  receivedMessage.value = message;
}
</script>

父组件监听子组件的 sendMessage 事件,通过 handleMessage 方法接收子组件传递过来的数据。

2. 跨级组件传值(provide/inject)

有时,我们需要在组件树中跨越多个层级进行数据传递,而不希望通过 props 一层一层传递。这时,provideinject 就显得非常有用。

2.1 provideinject 的基本使用

在 Vue 3 中,provideinject 是 Composition API 的一部分,允许在祖先组件和子孙组件之间共享数据,避免了中间组件需要显式地传递 props

父组件(祖先组件)代码

<template>
  <ChildComponent />
</template>

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

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

在祖先组件中使用 provide 提供数据,这里的键是 sharedData,值是字符串 "Shared data from Parent"

深层子组件代码

<template>
  <p>{{ data }}</p>
</template>

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

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

深层子组件使用 inject 获取祖先组件提供的 sharedData,不需要父子直接传值的路径。这在组件层级较多的应用中非常有用。

3. 全局状态管理

对于更大规模的应用,全局状态管理工具能帮助我们更好地组织和维护状态。Vue 3 推荐使用 Pinia 来替代 Vuex,它更加轻量且符合 Vue 3 的 Composition API 思想。

3.1 使用 Pinia 管理状态

安装 Pinia

npm install pinia

创建一个 store

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

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++;
    }
  }
});

这是一个简单的 counter store,使用 state 来定义状态,用 actions 来定义业务逻辑。

在组件中使用 Pinia

<template>
  <div>
    <p>Current Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

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

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

通过 Pinia,状态管理变得非常简洁,且状态和逻辑可以方便地在多个组件中共享。

4. v-model 实现双向绑定

在 Vue 3 中,v-model 得到了增强,允许为组件创建多个 v-model 绑定属性,使得数据流更加灵活和方便。

父组件代码

<template>
  <CustomInput v-model:text="textValue" v-model:number="numberValue" />
</template>

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

const textValue = ref('Default text');
const numberValue = ref(42);
</script>

在父组件中,通过 v-model:textv-model:number 可以分别绑定两个不同的值。

子组件代码

<template>
  <div>
    <input :value="text" @input="$emit('update:text', $event.target.value)" />
    <input type="number" :value="number" @input="$emit('update:number', $event.target.value)" />
  </div>
</template>

<script setup>
defineProps({
  text: String,
  number: Number
});

defineEmits(['update:text', 'update:number']);
</script>

子组件通过 emitupdate 事件实现与父组件的数据同步,形成双向绑定的效果。

5. 总结

Vue 3 提供了多种灵活的传值方式,涵盖了从简单的父子组件通信到复杂的全局状态管理。常见的方式有:

  • propsemit:适用于父子组件通信。

  • provideinject:适用于跨级组件传值。

  • Pinia:适合全局状态管理,尤其是大型应用。

  • v-model:增强的双向绑定适用于复杂表单或组件的同步。

通过合理选择这些传值方式,可以有效地组织 Vue 3 应用中的数据流,提升代码的可维护性和扩展性。

- END -

如果您关注前端+AI 相关领域可以扫码进群交流

 8b9ff32d9feb6f5f2ea88c3ed17e7f3a.jpeg

添加小编微信进群😊

关于奇舞团

奇舞团是 360 集团最大的大前端团队,非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

92e913dcd5c373b4044a8d9daf6b6d52.png

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐