主要内容
1、 props(父传子)
2、$emit触发自定义事件(子传父)(向上通信)
3、ref(索引,调用子组件的属性和方法,不擅长传递数据。在dom元素时,常用于选择器)
4、 EvenBus(兄弟之间传递)
5、parent与root(共同祖辈)
6、attrs与listeners(祖先传子孙)
7、Provide与inject(Provide组件)
8、Vuex状态管理(vue2使用)
9、pinia状态管理(vue3使用)
子传递父
一、props(父传子)
1、传递:父组件传递数据给子组件
2、使用
<template>
<div>
<div style="color: pink;">子组件</div>
<p>{{ message }}</p>
<p>{{ name }}</p>
<p>{{ age }}</p>
</div>
</template>
<script setup lang="ts">
import { defineProps } from 'vue';
defineProps<{
message: string;
name: string;
age: number;
}>();
</script>
<style scoped>
</style>
<template>
<div>
<div style="color: skyblue;">Prop 父组件</div>
<PropsSon :message="parentMessage" :name="parentName" :age="parentAge" />
</div>
</template>
<script setup lang="ts">
import PropsSon from './son.vue';
const parentMessage = 'Hello from Father!';
const parentName = 'Amy';
const parentAge = 18;
</script>
二、$emit触发自定义事件(子传父)(向上通信)
1、传递:子组件传递数据给父组件
2、使用
<template>
<div>
<div style="color: skyblue;">父组件</div>
<p>来自子组件的消息: {{ message }}</p>
<ChildComponent @update:message="handleMessage" />
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue';
import ChildComponent from './son.vue';
const message = ref('');
function handleMessage(data: string) {
message.value = data;
}
</script>
<template>
<div style="color: pink;">子组件</div>
<button @click="notifyParent">通知父组件</button>
</template>
<script setup lang='ts'>
import { defineEmits } from 'vue';
const emit = defineEmits(['update:message']);
function notifyParent() {
emit('update:message', 'Hello from child');
}
</script>
三、ref(索引,调用子组件的属性和方法,不擅长传递数据。在dom元素时,常用于选择器)
1、ref 本身并不是用来传递数据的。
在 Vue 中,数据通常通过 props 从父组件传递到子组件,通过自定义事件 ($emit 或在 <script setup> 中直接使用 emit 函数) 从子组件传递回父组件。
然而,ref 可以被用来在组件之间共享响应式数据(尽管这通常不是推荐的做法,因为它增加了组件之间的耦合度)
-
响应式数据:在组合式 API (
<script setup>) 中,ref通常用于创建一个响应式的引用对象,该对象内部包含一个值,并且当这个值改变时,视图会自动更新。例如:<script setup> import { ref } from 'vue'; const count = ref(0); </script> <template> <p>{{ count }}</p> </template> -
访问 DOM 元素:当
ref被用作模板引用(即在模板中通过ref="someRef"绑定到元素上)时,你可以在<script setup>中通过相同的引用名(需要加上.value来访问 DOM 元素,但在模板或计算属性/侦听器中不需要)来获取到这个 DOM 元素。但是,这并不是ref的主要目的,而是它的一个额外功能。 \ -
访问子组件实例:类似于访问 DOM 元素,当你将
ref绑定到一个子组件上时,你可以在父组件中通过该引用访问子组件的实例。这允许你调用子组件的方法或访问其属性。但是,这通常不是推荐的做法,因为它增加了组件之间的耦合度。
<template>
<div>
<button @click="notifyParent">通知父组件</button>
</div>
</template>
<script setup lang="ts">
import { defineEmits } from 'vue';
const emit = defineEmits(['update:message']);
function notifyParent() {
emit('update:message', 'Hello from child');
}
</script>
<template>
<div>
<p>来自子组件的消息: {{ message }}</p>
<ChildComponent @update:message="handleMessage" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './son.vue';
const message = ref('');
function handleMessage(data: string) {
message.value = data;
}
</script>
四、EvenBus(兄弟之间传递)
1、发送者、接收者、传递数据
export class EventBus {
private callbacks: Record<string, Array<(...args: any[]) => void>> = {};
static $emit: any;
$on(event: string, callback: (...args: any[]) => void) {
if (!this.callbacks[event]) {
this.callbacks[event] = [];
}
this.callbacks[event].push(callback);
}
$emit(event: string, ...args: any[]) {
if (this.callbacks[event]) {
this.callbacks[event].forEach(callback => callback(...args));
}
}
$off(event: string, callback: (...args: any[]) => void) {
if (this.callbacks[event]) {
this.callbacks[event] = this.callbacks[event].filter(cb => cb !== callback);
}
}
}
export const eventBus = new EventBus();
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script setup lang="ts">
import { eventBus } from './eventBus.ts';
const sendMessage = () => {
eventBus.$emit('message-sent', 'Hello from Sender');
};
</script>
<template>
<div>
<p>Received Message: {{ message }}</p>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { eventBus } from './eventBus.ts';
const message = ref('');
onMounted(() => {
eventBus.$on('message-sent', (msg) => {
message.value = msg;
});
});
</script>
注意:在 Vue 组件中通常不建议使用全局事件总线(EventBus)来传递数据或事件,因为这可能会导致组件之间的紧密耦合和难以追踪的依赖关系。在 Vue 3 中,你可以考虑使用 Vue 3 的 Composition API 提供的 provide 和 inject 功能,或者 Vuex、Vue 3 的响应式状态管理库 Pinia 等更现代的状态管理解决方案来管理跨组件的状态和事件。
五、parent与root(共同祖辈)
parent 和 root(或共同祖辈的概念,更准确地说是根组件)通常是通过组件的层级结构来体现的。
<template>
<div>
<h1>我是父组件</h1>
<p>来自子组件的消息:{{ messageData }}</p>
<Child :parentMessage="messageFromParent" @childEvent="handleChildEvent" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Child from './Child.vue';
const messageFromParent = ref('来自父组件的消息');
const messageData = ref('')
function handleChildEvent(message: string) {
messageData.value = message
}
</script>
<template>
<div>
<h2>我是子组件</h2>
<p>{{ parentMessage }}</p>
<button @click="sendMessageToParent">发送消息给父组件</button>
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
defineProps<{
parentMessage: string;
}>();
const emit = defineEmits<{
(e: 'childEvent', message: string): void;
}>();
function sendMessageToParent() {
emit('childEvent', '来自子组件的消息');
}
</script>
Root Component:在Vue3中,根组件通常通过createApp(App)挂载的那个组件(比如App.vue)
import { createApp } from 'vue'
import App from './App.vue'
import { router } from '@/routers'
createApp(App).use(router).mount('#app')
六、attrs与listeners(祖先传子孙)
<template>
<div>
<div style="color: orange;">祖先</div>
<p>来自子孙组件的消息:{{ Childdata }}</p>
<father :grandchild-message="grandchildMessage" @child-event="handleChildEvent" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Father from './father.vue';
const grandchildMessage = ref('来自祖先的消息');
const Childdata = ref('')
function handleChildEvent(message: string) {
Childdata.value = message
}
</script>
<template>
<div>
<div style="color: skyblue;">父组件</div>
<Son v-bind="$attrs" v-on:child-event="$emit('child-event', $event)" />
</div>
</template>
<script setup lang="ts">
import Son from './son.vue';
</script>
<template>
<div>
<h3 style="color: pink;">我是子孙组件</h3>
<button @click="sendMessageToAncestor">发送消息给祖先组件</button>
</div>
</template>
<script setup lang="ts">
import { defineEmits } from 'vue';
const emit = defineEmits<{
(e: 'child-event', message: string): void;
}>();
function sendMessageToAncestor() {
emit('child-event', '来自子孙组件的消息');
}
</script>
七、Provide与inject(Provide组件)
在Vue 3中,provide 和 inject 是用于实现跨组件层级通信的API。provide 选项允许你指定你想要提供给后代组件的数据/方法,而 inject 选项则用于接收这些数据/方法。
<template>
<div>
<div style="color:skyblue;">我是父组件</div>
<ChildComponent/>
</div>
</template>
<script setup>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const theme = ref('dark');
provide('theme', theme);
</script>
<template>
<div>
<h2 style="color:orange;">我是子组件</h2>
<GrandchildComponent/>
</div>
</template>
<script setup>
import GrandchildComponent from './GrandchildComponent.vue';
</script>
<template>
<div>
<h3 style="color:pink;">我是孙子组件,当前主题是:{{ theme }}</h3>
</div>
</template>
<script setup>
import { inject } from 'vue';
const theme = inject('theme', 'default'); // 第二个参数是默认值,可选
</script>
Vuex和pinia区别 状态管理Vuex和pinia区别
八、Vuex状态管理(vue2使用)
Vuex 的核心概念包括:
1、 State:单一状态树,用一个对象就包含了全部的应用层级状态。
2、Getters:允许组件从 Store 中获取数据,就像计算属性一样。
3、Mutations:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
Mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type) 和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更新的地方,并且它会接受 state 作为第一个参数。
4、Actions:Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。
5、Modules:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决这个问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
九、pinia状态管理(vue3使用)
Pinia是Vue的一个状态管理库,特别是为Vue 3设计,提供了一种简单、直观且可扩展的方式来组织和访问应用程序的状态。以下是关于Pinia状态管理的详细介绍:
一、Pinia的特点
1、轻量级与易用性:Pinia相比Vuex更加轻量级,减少了不必要的复杂性和概念。它的API设计更加简单直观,特别是利用了Vue 3的新特性,如Composition API,使得开发者能够更容易地上手和使用。
2、模块化状态管理:Pinia支持将状态划分为不同的模块,提高了代码的可维护性和可扩展性。每个模块可以包含自己的state、getters和actions,使得状态管理更加清晰和有条理。 T
3、ypeScript支持:Pinia提供了对TypeScript的良好支持,包括类型推断和自动补全功能,使得在TypeScript项目中使用Pinia更加方便。这有助于在开发过程中捕获错误和进行静态类型检查。
4、状态订阅与变更:Pinia允许开发者订阅状态的变化,并在状态发生变化时触发相应的回调函数。同时,它也支持使用patch方法来批量更新状态,以及通过reset方法将状态重置为初始值。
5、与Vue.js生态系统的集成:Pinia与Vue.js的其他工具和库配合良好,可以轻松地与Vuex、Vue Router等一起使用。
此外,它还支持Vue Devtools,方便开发者进行调试。 插件系统:Pinia允许通过插件来扩展其功能,例如支持服务端渲染或添加额外的中间件。
二、Pinia的核心概念Store:
1、Store:Pinia中的Store是一个保存状态和业务逻辑的实体,它不与组件树绑定,可以在整个应用中访问。
Store包含三个核心概念:state(状态)、getters(获取器)、actions(动作)。
state:状态数据,通常是响应式的,可以在组件中被读取和修改。
getters:计算属性,用于派生状态,它们是响应式的,并且可以被缓存。
actions:可以包含任意的异步操作或同步操作,用于修改状态或执行复杂的业务逻辑。