面试官:请你聊聊Vue中常见的组件通信方式。
前言
在Vue中组件通信是最强大的功能之一,但是组件的作用域是相互独立的,意味着不同组件之间的数据无法相互进行直接的引用,所以组件之间的通信非常重要。
常见的几种组件通信方式
父组件通过 props 向子组件传递数据,子组件通过 emit 和父组件通信。
1. Props(父传子)
-
定义:Props 是父组件向子组件传递数据的一种方式。父组件通过在子组件标签上设置属性的方式来传递数据,子组件则通过
props
选项来声明它预期接收的数据。 -
使用方法:
- 父组件:在子组件标签上绑定变量或表达式。
<!-- 父组件 -->
<template>
<ChildComponent :message="parentMessage" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return {
parentMessage: 'Hello from Parent'
};
}
};
</script>
- 子组件:在
props
选项中声明期望接收的属性。
// 子组件
export default {
props: ['message'],
mounted() {
console.log(this.message); // 输出: Hello from Parent
}
};
2. emit (子传父)
-
定义:当需要从子组件向父组件传递数据或事件时,可以使用 Vue 的自定义事件系统。子组件通过
emit
方法触发一个事件,并可以携带数据,父组件则监听这个事件。 -
使用方法:
- 子组件:触发一个自定义事件,并传递数据(如果需要)。
<script setup>
const emits = defineEmits(["child-event"]);//创建一个事件
onMounted() => {
//给到父组件
emits("child-event", 'hello')//发布事件
}
</script>
- 父组件:在模板中使用
v-on
或简写的@
监听子组件的事件。
<template>
<ChildComponent @child-event="parentMethod" />
</template>
<script>
// ...
methods: {
parentMethod(dataFromChild) {
console.log(dataFromChild); // 处理子组件传递过来的数据 hello
}
}
</script>
3. v-model双向数据绑定(子传父)
- 子组件
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">添加</button>
</div>
</template>
<script setup>
import {ref} from "vue"
const value=ref(" ")
const props=defineProps({
list:{
type:Array,
default:()=>[]
}
})
const emits=defineEmits(["update:list"])
const add=()=>{
//props.list.push(value.value) //不建议直接操作父组件给过来的数据
const arr =props.list;
arr.push(value.value)
emits("update:list",arr)//抛出来修改后的数组,在父组件中有v-model: 会促使它去修改数据
}
</script>
<style lang="css" scoped>
</style>
- 接收数据:子组件通过
defineProps
接收来自父组件的list
数据,类型为数组。 - 定义事件:使用
defineEmits
定义了一个名为"update:list"
的自定义事件,用于通知父组件更新list
。 - 数据绑定与修改:子组件内部使用
v-model
绑定了一个局部响应式变量value
到输入框,初始值为空字符串。用户在输入框中输入文本时,value
的值会随之改变。 - 按钮点击事件:当用户点击“添加”按钮时,触发
add
方法。此方法中,首先创建了一个父组件list
的副本arr
,然后将value
的值添加到arr
中。接着,通过emits("update:list", arr)
触发自定义事件,并将修改后的数组作为参数传递给父组件。 - 父组件响应:父组件监听到
update:list
事件后,会自动更新其list
的值,从而导致页面上显示的列表项更新,新增了用户输入的文本。
- 父组件
<template>
<Child v-model:list="list"></Child>
<div class="child">
<ul>
<li v-for="item in list">
{{ item }}
</li>
</ul>
</div>
</template>
<script setup>
import Child from "@/components/child3.vue";
import { ref } from "vue"
const list = ref(["html", "css", "js"])
</script>
<style lang="css" scoped></style>
- 数据初始化:父组件使用
ref
创建了一个响应式数组list
,初始值为["html", "css", "js"]
。 - 子组件使用:通过
v-model:list
指令将list
绑定到子组件Child
上。这里v-model
是一个语法糖,实际上绑定了list
作为 prop (list
) 并监听update:list
事件来更新list
的值。由于v-model
默认对应value
prop 和input
事件,但在这里通过model
属性显式指定了使用list
prop 和对应的事件名称update:list
。
整个过程中,子组件通过自定义事件将修改后的数据通知给父组件,父组件利用 v-model
的特性自动处理了数据的更新,实现了数据的双向绑定。注意子组件中直接操作 props
的做法是不推荐的,因此通过创建 arr
副本来避免直接修改父组件传递的数据。
4. defineExpose暴露数据 (子传父)
- 子组件
<template>
<div>
<p>{{ message }}</p>
<button @click="incrementCounter">点击增加计数</button>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const message = ref('你好,我是子组件');
const counter = ref(0);
const incrementCounter = () => {
counter.value++;
};
// 使用 defineExpose 暴露 message 和 incrementCounter 给父组件
defineExpose({
message,
incrementCounter
});
</script>
在这个子组件中,我们定义了两个响应式数据:message
和 counter
,以及一个方法 incrementCounter
。通过 defineExpose
,我们将 message
和 incrementCounter
暴露给父组件。
- 父组件
<template>
<div>
<ChildComponent ref="childRef" />
<button @click="displayMessage">显示子组件消息</button>
<button @click="increaseCounter">调用子组件方法增加计数</button>
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
const childRef = ref(null);
const displayMessage = () => {
alert(childRef.value.message);
};
const increaseCounter = () => {
childRef.value.incrementCounter();
};
</script>
在父组件中,我们首先通过模板引用 ref="childRef"
获取了子组件的实例。然后,定义了两个按钮,分别调用 displayMessage
和 increaseCounter
方法。这两个方法通过 childRef.value
访问到了子组件暴露出来的 message
和 incrementCounter
。
本篇文章就到此为止啦,希望通过这篇文章能对你理解Vue组件通信
有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。
转载自:https://juejin.cn/post/7385752495535964175