Vue3 数据通信方式全面解析

前言:Vue3 提供了多种数据通信方式,适用于不同场景的组件间通信需求。以下是8种主要通信方式的详细说明和示例:

1. Props & Emits (父子组件通信)

适用场景:直接的父子组件通信

<!-- 父组件 -->
<template>
  <ChildComponent 
    :title="parentTitle" 
    @update-title="handleUpdate"
  />
</template>

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

const parentTitle = ref('初始标题');
const handleUpdate = (newTitle) => {
  parentTitle.value = newTitle;
};
</script>

<!-- 子组件 Child.vue -->
<template>
  <div>
    <h1>{{ title }}</h1>
    <button @click="$emit('update-title', '新标题')">更改标题</button>
  </div>
</template>

<script setup>
defineProps(['title']);
defineEmits(['update-title']);
</script>

2. Provide & Inject (跨层级组件通信)

适用场景:祖先组件向后代组件传递数据,无需逐层传递props

<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue';

const counter = ref(0);
provide('counter', {
  counter,
  increment: () => counter.value++
});
</script>

<!-- 后代组件 -->
<script setup>
import { inject } from 'vue';

const { counter, increment } = inject('counter');
</script>

3. $attrs (非props属性传递)

适用场景:传递未被props接收的属性

<!-- 父组件 -->
<template>
  <ChildComponent class="child-class" data-test="123" />
</template>

<!-- 子组件 -->
<template>
  <div v-bind="$attrs">将接收所有非props属性</div>
</template>

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

const attrs = useAttrs();
console.log(attrs); // { class: 'child-class', 'data-test': '123' }
</script>

4. $refs & $parent (组件实例访问)

适用场景:直接访问组件实例(谨慎使用,破坏封装性)

<!-- 父组件 -->
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">调用子组件方法</button>
</template>

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

const childRef = ref(null);
const callChildMethod = () => {
  childRef.value.childMethod();
};
</script>

<!-- 子组件 -->
<script setup>
const childMethod = () => {
  console.log('子组件方法被调用');
};

// 暴露方法给模板ref
defineExpose({
  childMethod
});
</script>

5. Template Refs(模板引用)

适用场景:在 Vue 组件的模板中标记一个 DOM 元素或子组件

<!-- 父组件 -->
<template>
  <ChildComponent ref="child" />
  <button @click="child.method()">调用子组件方法</button>
</template>

<script setup>
import { ref } from 'vue';
const child = ref(null);
</script>

<!-- 子组件 -->
<script setup>
const method = () => console.log('方法被调用');
defineExpose({ method });
</script>

6. v-model (双向绑定)

适用场景:简化父子组件双向数据绑定

<!-- 父组件 -->
<template>
  <ChildComponent v-model="message" />
  <p>父组件消息: {{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';
const message = ref('初始消息');
</script>

<!-- 子组件 -->
<template>
  <input 
    :value="modelValue" 
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script setup>
defineProps(['modelValue']);
defineEmits(['update:modelValue']);

// Vue 3.4 开始就很简单不用定义emit和props,使用 defineModel('名字')
// const visible = defineModel('visible')
// 可以.value进行修改
// visible.value = false
</script>

 vue2中使用

<!-- 父组件 visibleQuery:false -->
<Query v-model="visibleQuery" />

<!-- 子组件 -->
<template>
  <a-modal title="查看" :visible="value"@cancel="$emit('input', false)">
   123
  </a-modal>
</template>

<script>
export default { name: 'Query', props: ['value'] }
</script>

7. Slot (插槽通信)

适用场景:内容分发和子向父传递数据

默认插槽、具名插槽...

作用域插槽

<!-- 父组件 -->
<ChildComponent v-slot="{ user }">
  {{ user.name }}
</ChildComponent>

<!-- 子组件 -->
<template>
  <div>
    <slot :user="userData"></slot>
  </div>
</template>

<script setup>
const userData = { name: '张三', age: 30 };
</script>

8. Pinia (状态管理)

适用场景:全局状态管理

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

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

// 组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter';

const counter = useCounterStore();
</script>

<template>
  <div>{{ counter.count }}</div>
  <div>{{ counter.doubleCount }}</div>
  <button @click="counter.increment()">增加</button>
</template>

通信方式选择指南

通信方式适用场景优点缺点
Props & Emits父子组件直接通信明确的数据流,易于理解多层组件需逐层传递
Provide/Inject跨层级组件通信避免props逐层传递数据来源不够透明
$attrs传递非props属性灵活传递属性可能造成属性混乱
$refs & $parent直接访问组件实例可直接调用方法破坏组件封装性
ref共享简单状态共享轻量级实现不适合大型应用
v-model父子组件双向绑定语法简洁仅限于简单数据绑定
Slot内容分发和子向父通信灵活的内容组合复杂逻辑可能难以维护
Pinia全局状态管理集中式状态管理,功能强大增加项目复杂度

后记:根据具体场景选择合适的通信方式,简单场景优先使用Props/Emits和Provide/Inject,复杂应用建议使用Pinia进行状态管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值