Vue父子组件通讯的四种方法详解
作者:睡着学
父子组件通讯
父子组件通讯是指在前端开发的组件化架构中,父组件与子组件之间互相传递数据和触发功能的一种机制。这种机制使得组件能够保持独立性的同时,也能协同工作,完成复杂的界面逻辑和数据交互。
通过一个用vue实现的demo为例:
在这个demo中:
- 需要使用
v-model
指令将文本框内的内容与变量进行双向绑定,用于获取文本框内的内容。 - 通过一个数组存储需要展示的内容,并且使用
v-for
遍历数组内的内容然后渲染。 - 通过
@click='add'
为按钮添加一个点击事件将文本框的输入内容添加到数组上。
//组件一 <div class="input-group"> <input type="text" v-model="item"> <button @click="add">添加</button> </div> //组件二(需要数据) <div class="child"> <ul> <li v-for="item in list">{{ item }}</li> </ul> </div>
如果我们将组件一放在父组件内,将组件二放在子组件,那我们要怎么将父组件中数据传递给子组件进行渲染呢?(组件二需要数据)
这个时候就需要进行父子组件的通讯。
父向子通讯
父组件向子组件传递信息非常方便,通过子组件的属性传递数据就好了。
组件一放在父组件,组件二放在子组件中。父组件将值v-bind
绑定传给子组件,子组件使用defineProps
接受。
父组件:在<Child :toChild="toChild"></Child>
中用v-bind绑定toChild
变量传递给子组件。
<template> <div class="input-group"> <input type="text" v-model="item"> <button @click="add">添加</button> </div> //将数据传递给子组件 <Child :toChild="toChild"></Child> </template> <script setup> import Child from '@/components/child1.vue' import { ref } from "vue"; const item = ref('') const toChild = ref('') const add = () => { toChild.value = item.value item.value = '' } </script>
子组件:子组件用defineProps
接受父组件传递的数据并且通过设置一个watch
监听器,当父组件通过toChild
属性传递一个新的值,这个值就会被添加到子组件的列表中。
<template> <div class="child"> <ul> <li v-for="item in list">{{ item }}</li> </ul> </div> </template> <script setup> import { defineProps } from 'vue' import { reactive, watch } from "vue"; const list = reactive(['html', 'css', 'javascript']) //接收父组件的数据 const props = defineProps({ toChild: '' }) //监听数据的改变动态添加到数组里 watch(() => props.toChild, (newVal, oldVal) => { list.push(newVal) }) </script>
子向父通讯
子组件向父组件传递数据较为麻烦一点,常见的方法是通过自定义事件实现数据的传递。
将组件二放在父组件,将组件一放在子组件里。
方法一
借助发布订阅机制,子组件负责发布事件携带参数,父组件订阅该事件通过事件参数获取子组件提供的值。
子组件:通过defineEmits
定义并创建一个add
事件,再通过触发点击事件的处理函数用emits
发布add
事件,并且携带数据。
<template> <div class="input-group"> <input type="text" v-model="item"> <button @click="add">添加</button> </div> </template> <script setup> import { ref } from "vue"; const item = ref('') const emits = defineEmits(['add'])//创建一个add事件 const add = () => { //将item变量给到父组件 emits('add', item.value)//发布add事件 item.value = '' } </script>
父组件:通过<child @add="handle"></child>
给子组件绑定自定义的add
事件并且以handle
函数作为处理函数。当add
事件发布时,就会触发执行handle
函数并且通过handle
函数的参数接收子组件传递的数据。
<template> <!-- 订阅add事件,子组件什么时候发布add事件,父组件就会执行handle函数,从而实现数据的共享 --> <child @add="handle"></child> <div class="child"> <ul> <li v-for="item in list">{{ item }}</li> </ul> </div> </template> <script setup> import child from '@/components/child2.vue' import { reactive } from "vue"; const list = reactive(['html', 'css', 'javascript']) const handle = (value) => { list.push(value) } </script>
这种方法中子组件只需要发布自定义事件并且携带数据,父组件只需要监听自定义事件并且接受数据。
方法二
父组件借助v-model
将数据绑定给子组件,子组件创建update:xxx
事件,并接收到该数据将修改后的数据emits(发布)出来让父组件接收修改后的数据。
父组件:在<child v-model:list="list"></child>
中,使用v-model:list
将父组件中的 list
数据(渲染数组)传递给子组件并且进行绑定,当子组件发布 update:list
事件后,父组件将接收到修改后的渲染数组并且进行重新渲染。
<template> <div> <child v-model:list="list"></child> <div class="child"> <ul> <li v-for="item in list">{{ item }}</li> </ul> </div> </div> </template> <script setup> import child from '@/components/child3.vue' import {reactive } from "vue"; const list = reactive(['html', 'css', 'javascript']) </script>
子组件:子组件通过defineProps
接收父组件发送的list
,并且自定义一个Update:list
事件。当点击按钮后触发add
函数,将文本框数据放入list
中,然后发布Update:list
事件并且携带着修改后的list
。随着Update:list
事件的发布,父组件就可以接收到修改后的list
。
<template> <div> <div class="input-group"> <input type="text" v-model="item"> <button @click="add">添加</button> </div> </div> </template> <script setup> import { ref } from "vue"; const item = ref('') const props = defineProps({ list: { type: Array, default: () => [] } }) const emits = defineEmits(['Update:list']) const add = () => { const arr = props.list arr.push(item.value) emits('Update:list', arr) item.value = '' } </script>
这种方法使父组件的操作变得简洁,但将子组件的操作变得复杂了。父组件只需要和子组件进行双向绑定数据就行了,子组件则需要接收数据再发布自定义的Update:xxx
事件将修改后的数据传递给父组件。
方法三
父组件通过ref
获取子组件中defineExprose()
暴露出来的数据。
子组件:使用 defineExpose
暴露数据,子组件通过defineExpose({ list })
将更新后的渲染数组暴露给父组件。
<template> <div class="input-group"> <input type="text" v-model="item"> <button @click="add">添加</button> </div> </template> <script setup> import { ref, reactive } from "vue"; const item = ref('') const list = reactive(['html', 'css', 'javascript']) const add = () => { list.push(item.value) item.value = '' } defineExpose({ list }) </script>
父组件:获取子组件的数据,使用 ref
定义一个引用变量来引用子组件,并在适当的时机获取子组件暴露的渲染数组。将子组件暴露的渲染数组作为v-for
的循环对象进行渲染。
<template> //获取子组件的引用 <child ref="childRef"></child> <div class="child"> <ul> //childRef?.list表示只有在在子组件已经挂载完成后才能访问子组件暴露的list数据 <li v-for="item in childRef?.list">{{ item }}</li> </ul> </div> </template> <script setup> import child from '@/components/child4.vue' import { ref, reactive, onMounted } from "vue"; //用ref定义一个引用变量 const childRef = ref(null); </script>
这种方法十分简便,子组件只需要暴露数据给父组件,然后父组件引用子组件暴露的数据,但是需要注意生命周期,需要在组件挂载完成后父组件才能成功获取子组件的数据。
以上就是Vue父子组件通讯的四种方法详解的详细内容,更多关于Vue父子组件通讯的资料请关注脚本之家其它相关文章!