Vue3.js组件通信,兄弟组件,父子、祖孙组件
在 Vue.js 3 中,组件通信主要包括父子组件通信、兄弟组件通信以及祖孙组件通信。以下是各种情况下的常见通信方式:
1. 父子组件通信:
1.1 Props 传递数据:
父组件通过 props 向子组件传递数据:
<!-- Parent.vue -->
<template>
<Child :message="parentMessage" />
</template>
<script>
import Child from './Child.vue';
export default {
data() {
return {
parentMessage: 'Hello from Parent!'
};
},
components: {
Child
}
};
</script>
<!-- Child.vue -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
};
</script>
1.2 事件监听子组件:
子组件通过 $emit 触发事件,父组件通过监听这些事件来响应:
<!-- Parent.vue -->
<template>
<Child @notifyParent="handleNotify" />
</template>
<script>
import Child from './Child.vue';
export default {
methods: {
handleNotify(message) {
console.log(message); // 处理从子组件传递的数据
}
},
components: {
Child
}
};
</script>
<!-- Child.vue -->
<template>
<button @click="notifyParent">Notify Parent</button>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('notifyParent', 'Hello from Child!');
}
}
};
</script>
1.3 definEexpose暴露子组件方法
在 Vue 3 中,使用 TypeScript 编写组件时,如果想要将子组件的方法暴露给父组件,可以使用 defineExpose
函数。defineExpose
允许你定义哪些内容应该被暴露给父组件,以供父组件访问。
下面是一个简单的例子,演示如何在子组件中使用 defineExpose
暴露方法:
// ChildComponent.vue
<template>
<div>
<button @click="incrementCounter">Increment Counter</button>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const counter = ref(0);
const incrementCounter = () => {
counter.value++;
};
// 暴露方法给父组件
defineExpose({
incrementCounter
});
</script>
在这个例子中,incrementCounter
方法被定义在子组件中,并通过 defineExpose
函数进行了暴露。父组件可以通过子组件的引用来调用这个方法。
// ParentComponent.vue
<template>
<div>
<ChildComponent ref="childRef" />
<button @click="callChildMethod">Call Child Method</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const childRef = ref();
const callChildMethod = () => {
// 调用子组件的方法
childRef.value.incrementCounter();
};
</script>
在父组件中,通过 ref
引用子组件,然后可以调用子组件中暴露的方法。
这样,通过 defineExpose
可以在 Vue 3 中很方便地实现子组件方法的暴露。这对于构建可重用组件库或复杂组件通信场景非常有用。
$attrs
批量绑定子组件事件
$attrs
是 Vue.js 中的一个属性,它在 Vue 2.4.0 及以后的版本中引入,并且在 Vue 3 中仍然保留,但其功能有所增强。$attrs
主要用于在组件之间传递未被子组件声明的属性(attributes)。
使用场景:
- 二次封装组件:当你想要封装一个组件,并希望将父组件传递给该组件的所有属性(除了已经作为 props 声明或自定义事件声明的属性)都传递给子组件时,可以使用
$attrs
。这样,你就不需要手动一一传递这些属性,而是直接通过$attrs
一次性传递。 - 多层嵌套组件:在多层嵌套的组件结构中,如果你想要将数据从顶层组件传递到深层的子组件,而不需要在每一层都使用 props 进行传递,那么
$attrs
可以帮助你实现这一需求。你只需要在顶层组件中一次性将数据作为属性传递给中间的包装组件,然后在包装组件中使用$attrs
将这些属性传递给它的子组件,以此类推,直到数据最终到达目标子组件。
使用方法
在模板中,你可以使用 v-bind
指令将 $attrs
绑定到子组件上,如下所示:
<template>
<div>
<child-component v-bind="$attrs"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
// ... 其他选项
};
</script>
在上面的示例中,<child-component>
会接收到父组件传递的所有未被子组件声明的属性。
注意事项
$attrs
不包括class
和style
属性,因为这两个属性有特殊的处理机制。- 在 Vue 3 中,
$attrs
还包含了父组件的事件监听器(即 Vue 2 中的$listeners
),因此你可以使用$attrs
来同时传递属性和事件监听器。 - 如果子组件已经声明了某个属性作为 prop,那么该属性将不会包含在
$attrs
中,因为它已经被子组件识别并处理。
2. 兄弟组件通信:
2.1 通过共享状态(使用父组件):
通过将状态提升到共同的父组件,然后通过 props 和事件来实现兄弟组件之间的通信。
2.2 使用事件总线(Bus):
创建一个事件总线,兄弟组件通过事件总线来通信。在 Vue 3 中,可以使用 provide/inject 来创建一个简单的事件总线。
// EventBus.js
import { createApp, ref } from 'vue';
const bus = createApp();
bus.provide('eventBus', bus);
// ComponentA.vue
<script>
export default {
methods: {
notifySibling() {
this.$root.eventBus.emit('siblingEvent', 'Hello from Component A!');
}
}
};
</script>
// ComponentB.vue
<script>
export default {
created() {
this.$root.eventBus.on('siblingEvent', message => {
console.log(message); // 处理从兄弟组件传递的数据
});
}
};
</script>
3. 祖孙组件通信:
3.1 通过 provide/inject:
使用 provide/inject 可以实现祖孙组件之间的通信,祖先组件通过 provide 提供数据,孙子组件通过 inject 获取数据。
<!-- Grandparent.vue -->
<template>
<Parent />
</template>
<script>
import { ref } from 'vue';
import Parent from './Parent.vue';
export default {
setup() {
const grandparentMessage = ref('Hello from Grandparent!');
provide('grandparentMessage', grandparentMessage);
return {
grandparentMessage
};
},
components: {
Parent
}
};
</script>
<!-- Parent.vue -->
<template>
<Child />
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child
}
};
</script>
<!-- Child.vue -->
<template>
<div>{{ grandparentMessage }}</div>
</template>
<script>
import { inject } from 'vue';
export default {
setup() {
const grandparentMessage = inject('grandparentMessage');
return {
grandparentMessage
};
}
};
</script>
4. Vuex(全局状态管理):
如果你的应用中需要管理全局状态,Vuex 是一个强大的状态管理库。通过将状态存储在 Vuex 中,不同组件可以通过 Vuex 的 store 来实现通信。
// store.js
import { createStore } from 'vuex';
export default createStore({
state: {
message: 'Hello from Vuex!'
},
mutations: {
updateMessage(state, newMessage) {
state.message = newMessage;
}
},
actions: {
changeMessage({ commit }, newMessage) {
commit('updateMessage', newMessage);
}
}
});
// ComponentA.vue
<script>
export default {
computed: {
message() {
return this.$store.state.message;
}
},
methods: {
changeMessage() {
this.$store.dispatch('changeMessage', 'New Message');
}
}
};
</script>
// ComponentB.vue
<script>
export default {
computed: {
message() {
return this.$store.state.message;
}
}
};
</script>
在 Vue.js 生态系统中,除了 Vuex
之外,还有一些其他状态管理库,其中包括 Pinia 和 Tini。这两个库提供了不同的方式来处理状态管理,和 Vuex 一样,它们都是 Vue 3 的状态管理库。
5. Pinia:
Pinia 是一个由 Vue.js 团队开发的状态管理库,旨在提供简单、灵活且性能出色的状态管理方案。与 Vuex 不同,Pinia 使用了更现代的 API,并且是基于 Composition API 构建的。
Pinia 的特点:
- 使用 Composition API 构建。
- 具有 TypeScript 支持。
- 基于 Vue 3 的响应式系统。
- 使用插件系统轻松扩展功能。
安装 Pinia:
npm install pinia
使用 Pinia:
import { createPinia } from 'pinia';
const pinia = createPinia();
export const useStore = pinia.createStore({
state: () => ({ count: 0 }),
actions: {
increment() {
this.state.count++;
}
}
});
6.mitt
mitt
是一个简单而小巧的事件总线库,用于在应用程序的不同部分之间进行事件通信。它提供了一种简单的方式来发射和监听事件。与 Vuex 的 $emit
和 $on
类似,但 mitt
更为轻量。
下面是 mitt
的基本用法:
import mitt from 'mitt';
// 创建事件总线
const emitter = mitt();
// 监听事件
emitter.on('custom-event', (data) => {
console.log('Event Received:', data);
});
// 发射事件
emitter.emit('custom-event', 'Hello from Mitt!');
在上面的代码中,emitter
是一个事件总线实例,可以用于在不同部分之间发送和接收事件。
更多推荐
所有评论(0)