VUE3 之 元件間事件通訊 - 這個系列的教程通俗易懂,適合新手

追風人聊Java發表於2022-01-24

1. 概述

相關定律告訴我們:這個世界上的任何事物之間都會存在一定聯絡,“城門失火,殃及池魚”就是一個很好的例子。因此如果我們能夠儘早發現這些看不見的聯絡,就能很好的解決更多遇見的難題。

 

言歸正傳,之前我們聊過如何在子元件中去修改主元件傳遞的引數的值,當時是在子元件中重新宣告一個新資料,初始值為父元件傳參的值,然後對子元件的資料進行計算。

今天我們使用事件的方式來實現對父元件的傳參進行修改。

 

2. 元件間事件通訊

2.1 子元件接收引數並實現自增

<body>
    <div id="myDiv"></div>
</body>
<script>
    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        template:`
            <div>
                <test :num="num" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.num++;
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });
    const vm = app.mount("#myDiv");

這個例子我們們之前聊過,父元件有一個資料 num,父元件將這個引數傳給 test 子元件,子元件使用 props:['num'] 的方式接收後,在事件方法中對其自增

 

 很明顯,自增時會報錯,因為父元件傳過來的 num 是隻讀的,子元件不能對其進行修改。

 

2.2 子元件中宣告新的資料,將父元件的num作為初始值

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        template:`
            <div>
                <test :num="num" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        data() {
            return {
                myNum : this.num
            }
        },
        methods : {
            incrNum() {
                // this.num++;
                this.myNum++;
            }
        },
        template:`
            <div @click="incrNum" >{{myNum}}</div>
        `
    });

這是我們上節課的解決方案,在子元件中宣告 myNum,把num當做初始值,然後自增 myNum,顯示時也顯示 myNum

 

很明顯,這樣做是可以的

 

2.3 子元件呼叫父元件的方法

既然子元件無權修改父元件傳過來的引數,那我們就讓父元件自己去修改這個引數

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        methods : {
            handleIncr() {
                this.num++;
            }
        },
        template:`
            <div>
                <test :num="num" @incrNum="handleIncr" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.$emit('incrNum')
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });

這個例子中,父元件在使用子元件時,繫結了一個事件 incrNum,這個事件會呼叫父元件的 handleIncr 方法,這個方法中對資料 num 進行了自增。

子元件在自己的 incrNum 方法中使用 this.$emit('incrNum') 觸發了父元件的 incrNum 事件,然後該事件呼叫父元件的 handleIncr 方法,對父元件的資料 num 進行修改。

父元件修改了資料 num,這個資料 num 修改後的值會傳遞給子元件,從而實現對 num 引數的修改。

 

說了這麼一大堆,簡單看就是子元件通過某種手段呼叫了父元件的方法。

 

經試驗,完全沒用問題,可以修改 num 的值

 

2.4 子元件呼叫父元件的方法,且傳參

光呼叫還不行,我們還要傳參

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        methods : {
            handleIncr(param1) {
                this.num += param1;
            }
        },
        template:`
            <div>
                <test :num="num" @incrNum="handleIncr" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.$emit('incrNum', 2)
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });

這個例子中,我們根據傳參的值,決定自增多少。

在 this.$emit('incrNum', 2) 這句程式碼中,除了指明觸發的事件,還傳了一個引數,父元件的 handleIncr(param1) 這個方法,就可以接收這個引數,並使用

 

2.5 子元件呼叫父元件的方法,且傳多個引數

這次我們要傳多個引數,當然也是可以的

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        methods : {
            handleIncr(param1, param2) {
                this.num += param2;
            }
        },
        template:`
            <div>
                <test :num="num" @incrNum="handleIncr" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.$emit('incrNum', 2, 3)
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });

這麼傳:this.$emit('incrNum', 2, 3),這麼收:handleIncr(param1, param2),以此類推

 

2.6 計算邏輯放在子元件中

自增本來是子元件的業務,我們不想把這個邏輯放到父元件中,耦合性太強了,我們可以這麼寫

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        methods : {
            handleIncr(param1) {
                this.num = param1;
            }
        },
        template:`
            <div>
                <test :num="num" @incrNum="handleIncr" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.$emit('incrNum', this.num + 1)
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });

其實就是傳參時在子元件中計算好了,然後父元件直接賦值就好

 

2.7 通過 v-model 的方式,修改父元件資料的值

上面的例子中,我們通過子元件呼叫父元件的方法去修改父元件資料的值,耦合性還是有點強,父元件需要去為子元件寫一個方法。

其實還有一個更簡潔的辦法,就是通過 v-model 的方式,來看下面的例子

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        template:`
            <div>
                <test v-model="num" />
            </div>
        `
    });
    app.component("test", {
        props:['modelValue'],
        methods : {
            incrNum() {
                this.$emit('update:modelValue', this.modelValue + 1);
            }
        },
        template:`
            <div @click="incrNum" >{{modelValue}}</div>
        `
    });

這個例子中,父元件使用 test 子元件時,使用 v-model="num" 的方式來傳參。

test 子元件接收時,使用 props:['modelValue'] 的方式接收,注意:modelValue 是一個固定寫法。

在子元件的自增方法中使用 this.$emit('update:modelValue', this.modelValue + 1); 的形式去修改 modelValue 的值,注意:update:modelValue 是固定寫法。

 

2.8 使用 num 替換 modelValue

上面的例子有點不好理解,無緣無故蹦出個 modelValue,父元件明明傳的是 num,為啥我接受要用 modelValue,太奇怪了

下面的例子更易於我們的理解

    const app = Vue.createApp({
        data() {
            return {
                num : 1
            }
        },
        template:`
            <div>
                <test v-model:num="num" />
            </div>
        `
    });
    app.component("test", {
        props:['num'],
        methods : {
            incrNum() {
                this.$emit('update:num', this.num + 1);
            }
        },
        template:`
            <div @click="incrNum" >{{num}}</div>
        `
    });

這個例子就好理解多了,首先父元件使用 test 子元件時,使用 v-model:num="num" 進行傳參。

子元件接收時,接收的就是 num,使用 props:['num'] 接收。

最後使用 this.$emit('update:num', this.num + 1);  程式碼對接收到的 num 進行修改。

顯示時顯示的也是 num,{{num}}

 

這樣寫就清爽很多,父元件沒有 method,子元件相當於自己對接收到的引數 num 進行操作,耦合度降低了很多。

 

3. 綜述

今天聊了一下 VUE3 的 元件間事件通訊,希望可以對大家的工作有所幫助,下一節我們繼續講元件的相關知識,敬請期待

歡迎幫忙點贊、評論、轉發、加關注 :)

關注追風人聊Java,每天更新Java乾貨。

 

4. 個人公眾號

追風人聊Java,歡迎大家關注

相關文章