Vue父子組件通訊的四種方法詳解
父子組件通訊
父子組件通訊是指在前端開發(fā)的組件化架構(gòu)中,父組件與子組件之間互相傳遞數(shù)據(jù)和觸發(fā)功能的一種機制。這種機制使得組件能夠保持獨立性的同時,也能協(xié)同工作,完成復(fù)雜的界面邏輯和數(shù)據(jù)交互。
通過一個用vue實現(xiàn)的demo為例:

在這個demo中:
- 需要使用
v-model指令將文本框內(nèi)的內(nèi)容與變量進行雙向綁定,用于獲取文本框內(nèi)的內(nèi)容。 - 通過一個數(shù)組存儲需要展示的內(nèi)容,并且使用
v-for遍歷數(shù)組內(nèi)的內(nèi)容然后渲染。 - 通過
@click='add'為按鈕添加一個點擊事件將文本框的輸入內(nèi)容添加到數(shù)組上。
//組件一
<div class="input-group">
<input type="text" v-model="item">
<button @click="add">添加</button>
</div>
//組件二(需要數(shù)據(jù))
<div class="child">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
如果我們將組件一放在父組件內(nèi),將組件二放在子組件,那我們要怎么將父組件中數(shù)據(jù)傳遞給子組件進行渲染呢?(組件二需要數(shù)據(jù))
這個時候就需要進行父子組件的通訊。
父向子通訊
父組件向子組件傳遞信息非常方便,通過子組件的屬性傳遞數(shù)據(jù)就好了。
組件一放在父組件,組件二放在子組件中。父組件將值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>
//將數(shù)據(jù)傳遞給子組件
<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接受父組件傳遞的數(shù)據(jù)并且通過設(shè)置一個watch監(jiān)聽器,當(dāng)父組件通過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'])
//接收父組件的數(shù)據(jù)
const props = defineProps({
toChild: ''
})
//監(jiān)聽數(shù)據(jù)的改變動態(tài)添加到數(shù)組里
watch(() => props.toChild, (newVal, oldVal) => {
list.push(newVal)
})
</script>
子向父通訊
子組件向父組件傳遞數(shù)據(jù)較為麻煩一點,常見的方法是通過自定義事件實現(xiàn)數(shù)據(jù)的傳遞。
將組件二放在父組件,將組件一放在子組件里。
方法一
借助發(fā)布訂閱機制,子組件負責(zé)發(fā)布事件攜帶參數(shù),父組件訂閱該事件通過事件參數(shù)獲取子組件提供的值。
子組件:通過defineEmits定義并創(chuàng)建一個add事件,再通過觸發(fā)點擊事件的處理函數(shù)用emits發(fā)布add事件,并且攜帶數(shù)據(jù)。
<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'])//創(chuàng)建一個add事件
const add = () => {
//將item變量給到父組件
emits('add', item.value)//發(fā)布add事件
item.value = ''
}
</script>
父組件:通過<child @add="handle"></child>給子組件綁定自定義的add事件并且以handle函數(shù)作為處理函數(shù)。當(dāng)add事件發(fā)布時,就會觸發(fā)執(zhí)行handle函數(shù)并且通過handle函數(shù)的參數(shù)接收子組件傳遞的數(shù)據(jù)。
<template>
<!-- 訂閱add事件,子組件什么時候發(fā)布add事件,父組件就會執(zhí)行handle函數(shù),從而實現(xiàn)數(shù)據(jù)的共享 -->
<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>
這種方法中子組件只需要發(fā)布自定義事件并且攜帶數(shù)據(jù),父組件只需要監(jiān)聽自定義事件并且接受數(shù)據(jù)。
方法二
父組件借助v-model將數(shù)據(jù)綁定給子組件,子組件創(chuàng)建update:xxx事件,并接收到該數(shù)據(jù)將修改后的數(shù)據(jù)emits(發(fā)布)出來讓父組件接收修改后的數(shù)據(jù)。
父組件:在<child v-model:list="list"></child>中,使用v-model:list 將父組件中的 list 數(shù)據(jù)(渲染數(shù)組)傳遞給子組件并且進行綁定,當(dāng)子組件發(fā)布 update:list 事件后,父組件將接收到修改后的渲染數(shù)組并且進行重新渲染。
<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接收父組件發(fā)送的list,并且自定義一個Update:list事件。當(dāng)點擊按鈕后觸發(fā)add函數(shù),將文本框數(shù)據(jù)放入list中,然后發(fā)布Update:list事件并且攜帶著修改后的list。隨著Update:list事件的發(fā)布,父組件就可以接收到修改后的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>
這種方法使父組件的操作變得簡潔,但將子組件的操作變得復(fù)雜了。父組件只需要和子組件進行雙向綁定數(shù)據(jù)就行了,子組件則需要接收數(shù)據(jù)再發(fā)布自定義的Update:xxx事件將修改后的數(shù)據(jù)傳遞給父組件。
方法三
父組件通過ref獲取子組件中defineExprose()暴露出來的數(shù)據(jù)。
子組件:使用 defineExpose 暴露數(shù)據(jù),子組件通過defineExpose({ list })將更新后的渲染數(shù)組暴露給父組件。
<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>
父組件:獲取子組件的數(shù)據(jù),使用 ref 定義一個引用變量來引用子組件,并在適當(dāng)?shù)臅r機獲取子組件暴露的渲染數(shù)組。將子組件暴露的渲染數(shù)組作為v-for的循環(huán)對象進行渲染。
<template>
//獲取子組件的引用
<child ref="childRef"></child>
<div class="child">
<ul>
//childRef?.list表示只有在在子組件已經(jīng)掛載完成后才能訪問子組件暴露的list數(shù)據(jù)
<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>
這種方法十分簡便,子組件只需要暴露數(shù)據(jù)給父組件,然后父組件引用子組件暴露的數(shù)據(jù),但是需要注意生命周期,需要在組件掛載完成后父組件才能成功獲取子組件的數(shù)據(jù)。
以上就是Vue父子組件通訊的四種方法詳解的詳細內(nèi)容,更多關(guān)于Vue父子組件通訊的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue?響應(yīng)式系統(tǒng)依賴收集過程原理解析
Vue 初始化時就會通過 Object.defineProperty 攔截屬性的 getter 和 setter ,為對象的每個值創(chuàng)建一個 dep 并用 Dep.addSub() 來存儲該屬性值的 watcher 列表,這篇文章主要介紹了Vue?響應(yīng)式系統(tǒng)依賴收集過程分析,需要的朋友可以參考下2022-06-06
element?table?數(shù)據(jù)量大頁面卡頓的解決
這篇文章主要介紹了element?table?數(shù)據(jù)量大頁面卡頓的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
vue+element+Java實現(xiàn)批量刪除功能
這篇文章主要介紹了vue+element+Java實現(xiàn)批量刪除功能,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-04-04
vue-cli4創(chuàng)建項目導(dǎo)入Element-UI踩過的坑及解決
這篇文章主要介紹了vue-cli4創(chuàng)建項目導(dǎo)入Element-UI踩過的坑及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04

