切換語言為:簡體

在 Vue 中父子元件之間互相通訊常用的四種方法

  • 爱糖宝
  • 2024-07-02
  • 2070
  • 0
  • 0

父子元件通訊

父子元件通訊是指在前端開發的元件化架構中,父元件與子元件之間互相傳遞資料和觸發功能的一種機制。這種機制使得元件能夠保持獨立性的同時,也能協同工作,完成複雜的介面邏輯和資料互動。

透過一個用vue實現的demo為例:

在 Vue 中父子元件之間互相通訊常用的四種方法

在這個demo中:

  1. 需要使用v-model指令將文字框內的內容與變數進行雙向繫結,用於獲取文字框內的內容。

  2. 透過一個數組儲存需要展示的內容,並且使用v-for遍歷陣列內的內容然後渲染。

  3. 透過@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>

這種方法十分簡便,子元件只需要暴露資料給父元件,然後父元件引用子元件暴露的資料,但是需要注意生命週期,需要在元件掛載完成後父元件才能成功獲取子元件的資料。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.