Vue 3 通信方式介绍

Vue 3 通信方式

1 父子组件通信

1.1 Props

父组件通过 props 向子组件传递数据。

示例代码:

<!-- 父组件 -->
<template>
  <Child :msg="msg" />
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';
const msg = ref('Hello from Parent');
</script>
<!-- 子组件 -->
<template>
  <div>{{ msg }}</div>
</template>
<script setup>
defineProps({
  msg: String
});
</script>

1.2 defineEmits

子组件通过 emit 触发事件向父组件发送消息。

示例代码:

<!-- 子组件 -->
<template>
  <button @click="emitData">Emit Data</button>
</template>
<script setup>
const emit = defineEmits(['update']);
const emitData = () => {
  emit('update', 'Data from Child');
};
</script>
<!-- 父组件 -->
<template>
  <Child @update="handleUpdate" />
</template>
<script setup>
import Child from './Child.vue';
const handleUpdate = (data) => {
  console.log(data); // 输出:Data from Child
};
</script>

1.3 $attrs

用于传递未被props声明的属性。

示例代码:

<!-- 父组件 -->
<template>
  <Child custom-attr="value" />
</template>
<!-- 子组件 -->
<template>
  <div>{{ $attrs['custom-attr'] }}</div>
</template>

1.4 $ref + defineExpose

通过ref引用子组件,并使用defineExpose暴露子组件的方法

示例代码:

<!-- 子组件 -->
<script setup>
defineExpose({
  someMethod() {
    console.log('Method called');
  }
});
</script>
<!-- 父组件 -->
<template>
  <Child ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Child from './Child.vue';
const childRef = ref();
onMounted(() => {
  childRef.value.someMethod(); // 输出:Method called
});
</script>

1.5 $parent

子组件通过$parent直接访问父组件

示例代码:

<!-- 子组件 -->
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
  console.log($parent.someData);
});
</script>

1.6 v-model

v-model props$emit 的语法糖,用于实现父组件和子组件之间的双向数据绑定
Vue3 支持多个 v-model 绑定,默认使用 modelValue 作为 propupdate:modelValue 作为事件。

示例代码:

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent v-model="parentValue" />
    <p>Parent value: {{ parentValue }}</p>
  </div>
</template>

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

const parentValue = ref('Initial value');
</script>
<!-- 子组件 -->
<template>
  <div>
    <input v-model="modelValue" />
  </div>
</template>

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

const props = defineProps({
  modelValue: String
});

const emits = defineEmits(['update:modelValue']);

const handleInput = (event) => {
  emits('update:modelValue', event.target.value);
};
</script>

2 兄弟,跨层组件通信

2.1 全局事件总线(mitt)

使用事件总线(如mittvue3-eventbus)实现兄弟组件通信

示例代码:

npm install mitt
// eventBus.js
import mitt from 'mitt';
export const emitter = mitt();
<!-- 组件A -->
<script setup>
import { emitter } from './eventBus';
const sendData = () => {
  emitter.emit('data', 'Hello from A');
};
</script>
<!-- 组件B -->
<script setup>
import { emitter } from './eventBus';
emitter.on('data', (data) => {
  console.log(data); // 输出:Hello from A
});
</script>

示例代码2:

import { createApp } from 'vue';
import mitt from 'mitt';
import App from './App.vue';

const emitter = mitt();
const app = createApp(App);
app.config.globalProperties.emitter = emitter;
app.mount('#app');

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

<script setup>
const { emitter } = getCurrentInstance().appContext.config.globalProperties;

const sendMessage = () => {
  emitter.emit('message', 'Hello from ComponentA');
};
</script>

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

<script setup>
const { emitter } = getCurrentInstance().appContext.config.globalProperties;

const sendMessage = () => {
  emitter.emit('message', 'Hello from ComponentA');
};
</script>

2.2 provide/inject

祖先组件通过provide提供数据,后代组件通过inject注入

示例代码:

<!-- 祖先组件 -->
<template>
  <ChildComponent />
</template>

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

const sharedData = ref('Shared Data');
provide('sharedData', sharedData);
</script>

<!-- 后代组件 -->
<template>
  <p>{{ sharedData }}</p>
</template>

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

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

2.3 Vuex

VuexVue.js 的官方状态管理库,用于管理应用程序的状态。

示例代码:

import { createStore } from 'vuex';

export default createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  actions: {
    increment(context) {
      context.commit('increment');
    }
  },
  getters: {
    getCount(state) {
      return state.count;
    }
  }
});

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

<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const count = computed(() => store.getters.getCount);

const increment = () => {
  store.dispatch('increment');
};
</script>

2.4 Pinia

PiniaVue.js 的轻量级状态管理库,用于管理应用程序的状态。

import { defineStore } from 'pinia';

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

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

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

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

2.5 自定义 Hooks(Composables)

使用 Vue 3 的 Composition API 创建可复用的逻辑,用于组件之间的通信。

// useCounter.ts
import { ref } from 'vue';

export const useCounter = () => {
  const count = ref(0);

  const increment = () => {
    count.value++;
  };

  return {
    count,
    increment
  };
};

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

<script setup>
import { useCounter } from '../composables/useCounter';

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

3. 总结

通信方式适用场景注意事项
Props/Events父子组件简单通信避免深层次传递
v-model表单/组件双向绑定支持多个绑定
Provide/Inject跨层级组件通信需配合响应式数据
Pinia/Vuex全局状态管理复杂项目推荐
自定义 Hooks逻辑复用替代 mixins 的推荐方案
事件总线任意组件间通信(小型项目)需手动维护事件监听/销毁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值