VUE3 之 组件间事件通信 - 这个系列的教程通俗易懂,适合新手

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 @clic
原文链接:,转发请注明来源!