在Vue 3中,组件间通信的方式与Vue 2大致相同,主要包括以下几种方式:
目录
一、props / $emit
使用props和$emit是Vue 3中最基本的组件间通信方式。一个组件可以通过props向它的子组件传递数据,子组件则可以通过$emit触发一个事件,并将数据传递给父组件。
父组件:
<template>
<child :message="msg" @update="handleUpdate"></child>
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child,
},
data() {
return {
msg: 'Hello, child!',
};
},
methods: {
handleUpdate(data) {
this.msg = data;
},
},
};
</script>
子组件:
<template>
<div>
<p>{{ message }}</p>
<button @click="handleClick">Update Message</button>
</div>
</template>
<script>
export default {
props: {
message: String,
},
methods: {
handleClick() {
this.$emit('update', 'New message from child');
},
},
};
</script>
二、$refs
使用$refs可以在父组件中访问子组件的属性和方法。
父组件:
<template>
<div>
<child ref="child"></child>
<button @click="handleClick">Call Child Method</button>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child,
},
methods: {
handleClick() {
this.$refs.child.sayHello();
},
},
};
</script>
子组件:
<template>
<div>
<p>Hello, I am a child component</p>
</div>
</template>
<script>
export default {
methods: {
sayHello() {
console.log('Hello from child component!');
},
},
};
</script>
三、provide / inject
使用provide和inject可以在祖先组件中向子孙组件传递数据,而不需要显式地通过props和$emit传递。
祖先组件:
<template>
<div>
<child></child>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child,
},
provide() {
return {
message: 'Hello from ancestor component!',
};
},
};
</script>
子孙组件:
<template>
<div>
<grandchild></grandchild>
</div>
</template>
<script>
import Grandchild from './Grandchild.vue';
export default {
components: {
Grandchild,
},
};
</script>
孙子组件:
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
inject: ['message'],
};
</script>
四、v-model
v-model相当于自定义事件的语法糖,雨溪可能觉得你使用自定义事件的方式进行组件间的通信,怕你写的代码太多了有点受累,于是就推出了v-model双向数据绑定的方式进行组件间的通信。其中v-model包括两种写法。
第一种:v-model:自定义事件名 ==>$emit('update:自定义事件名',值)
第二种:v-model= ==>$emit('update:model-value',值) 使用默认的事件名model-value
第一种方式代码示例:
<body>
<!-- 在子组件中使用点击按钮改变父组件中的值 -->
<div id="app">
num:{{num}}
<!-- v-model后面有属性名(随便定义) 则update后面也要加这个属性名 实现双向数据绑定 -->
<ds v-model:x="num"></ds>
</div>
</body>
<script>
let app = Vue.createApp({
data() {
return {
num: 1,
};
},
});
// 定义组件
app.component("ds", {
props: [],
data() {
return {
a: 1,
};
},
template: `
<button @click="add">a:{{a}}</button>
`,
methods: {
add() {
this.a++;
this.$emit("update:x", this.a);
},
},
});
app.mount("#app");
</script>
第二种方式代码示例:
<body>
<!-- 在子组件中使用点击按钮改变父组件中的值 -->
<div id="app">
num:{{num}}
<!-- v-model后面没有属性名(随便定义) 则update后面要加默认属性名:model-value 实现双向数据绑定 -->
<ds v-model="num"></ds>
</div>
</body>
<script>
let app = Vue.createApp({
data() {
return {
num: 1,
};
},
});
// 定义组件
app.component("ds", {
props: [],
data() {
return {
a: 1,
};
},
template: `
<button @click="add">a:{{a}}</button>
`,
methods: {
add() {
this.a++;
this.$emit("update:model-value", this.a);
},
},
});
app.mount("#app");
</script>
五、Vuex
Vuex 是一个状态管理库,它提供了一种集中式存储管理应用的所有组件所需的数据和状态的方式。
// store.js
import { createStore } from 'vuex';
const store = createStore({
state() {
return {
message: 'initial message'
};
},
mutations: {
updateMessage(state, message) {
state.message = message;
}
}
});
export default store;
// 发送事件的组件
import { mapMutations } from 'vuex';
export default {
methods: {
...mapMutations(['updateMessage']),
sendMessage() {
this.updateMessage('data from sender');
}
}
};
// 接收事件的组件
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['message'])
}
};