Vue.js进阶系列(7)--组件通信结合双向绑定

  在前面,小编已经陆陆续续为大家分享了很多知识点,那么今天要为大家分享的是将组件通信和双向绑定结合在一起。这个案例的需求是这样子的:
1.基本数据:父组件有数据num1和num2,子组件有数据number1和number2.
2.实现需求:
  ① 父传子:将父组件的num1和num2传递到子组件的numer1和number2;
  ② 双向绑定:通过input输入框实现子组件的number1和number2的双向绑定;
  ③子传父:将新的number1和number2传递到父组件的num1和num2中。
那么下面开始编写代码

一、父传子

结合我们前面学过的知识,父传子是通过props实现的,具体代码如下:

    <body>
        <!-- 父组件Vue实例模板 -->
        <div class="warp">
            <!-- 通过v-bind传递数据 -->
            <cnp :number1="num1" :number2="num2"></cnp>
        </div>
        
        <!-- 子组件cnp的模板 -->
        <template id="tem">
            <div>
                <h2>props:{{number1}}</h2>
                <h2>props:{{number2}}</h2>
            </div>
        </template>
        
        <script>
            
            var vm = new Vue({
                el:'.warp',
                data:{
                    num1:1,
                    num2:2
                },
                
                // 子组件的注册
                components:{
                    cnp:{
                        template:'#tem',
                        props:{
                            number1:Number,
                            number2:Number
                        }
                    }
                }
            })
        </script>
    </body>

  在本例中,依旧将Vue作为父组件,父组件data中的数据分别是num1和num2;将子组件cnp声明为局部组件,子组件内部的数据分别是number1和number2;然后在父组件的模板div中使用子组件cnp并通过v-bind执行将num1传递给number1,将num2传递给number2.需求①已经完成

二、双向绑定

  这个需求是,我们希望在输入框输入什么数字就将该数字传递到子组件中,通过v-model实现,编写代码如下:

<template id="tem">
    <div>
        <h2>props:{{number1}}</h2>
        <input type="text" v-model="number1">

        <h2>props:{{number2}}</h2>
        <input type="text" v-model="number2">
    </div>
</template>
双向绑定.gif

  没错,就是这个效果!实现的非常完美!下面继续第三个需求。正当小编十分开心准备实现下一个需求时,发生了不可思议的事情,令小编十分的震惊!!!那就是居然在控制台上有错!!!!!!


你为什么错?.JPG

没办法,知错就改,这是为人的准则对吧,让我们先来看看到底是什么错误

image.png

  嗯?什么?你看不懂?没关系,小编刚去百度了,这个的意思就是说当你使用v-model实现一些双向绑定的时候,是不可以修改props的数据的,应该使用data或者computed计算属性
  因为props的数据是由父组件传递过来的,如果用v-model也可以修改props中的数据,就意味着props的数据来源不单单有父组件,还有通过v-model实现的双向绑定的数据。
  试想一下,你男朋友前脚收了你的礼物,又背着你收了别的女生的礼物,这是绝对不允许的!你男朋友只能收你的礼物不准收其他女孩子的礼物!props也一样,数据来源只能是父组件。
image.png

  所以我们应该这样做:首先在子组件用data函数来接受props中的数据,然后v-model绑定的是子组件中data的变量。代码如下:

// ①第一步:用data函数接收props中要修改的数据
data(){
        return{
                dnumber1:this.number1,
                dnumber2:this.number2
        }                   
}
//②第二步: v-model绑定子组件中data的数据
<template id="tem">
    <div>
        <h2>props:{{number1}}</h2>
        <h2>data:{{dnumber1}}</h2>
        <input type="text" v-model="dnumber1">

        <h2>props:{{number2}}</h2>
        <h2>data:{{dnumber2}}</h2>
        <input type="text" v-model="dnumber2">
    </div>
</template>
//这段代码可以直接添加到components组件中,为方便观看,小编已经为你拨开了被上帝遮住的眼(#^.^#)

  在子组件的data函数声明了两个变量dnumber1、dnumber2来接收存放props中的number1、number2,然后在子组件的模板中,用v-model绑定dnumber1和dnumber2.效果如下:


正确的双向绑定.gif

  完美,data值随着输入框的改变而改变了。好啦,我知道你要说什么,props的值没有改变,因为这是下面的需求啦~

三、子传父

  想要props的值改变,就意味着父组件的数据也要改变,因为props的值是父组件传递过来的,所以我们要将子组件中变化的dnumber1和dnumber2的值传递到父组件中去。【子传父的三步骤是:发射--接收--处理】
  首先我们知道,v-model的本质是v-bind指令和input事件的组合【别问我为啥知道,因为我在 “Vue.js入门系列(8)--表单操作1 https://www.jianshu.com/p/e005fef1c3eb” 讲过,不认真听讲是要打小屁屁的╭(╯^╰)╮】,所以我们将上述 的v-model修改成下面的形式:

<!-- <input type="text" v-model="dnumber1"> -->
<input type="text" :value='dnumber1' @input='num1Input'>
<!-- <input type="text" v-model="dnumber2"> -->
<input type="text" v-model="dnumber2" @input='num2Input'>

  没错,就像你发现的,这里有input事件,我们将在input事件内部发射自定义的事件给父组件,具体代码如下:

methods:{
    num1Input(event){
         //将输入框的值传递到子组件的数据中
        this.dnumber1=event.target.value;
        //子组件向父组件发射事件
        this.$emit('num1change',this.dnumber1);
    },
    num2Input(event){
         //将输入框的值传递到子组件的数据中
        this.dnumber2=event.target.value;
        //子组件向父组件发射事件
        this.$emit('num2change',this.dnumber2);
    }
}

  呼叫父组件!呼叫父组件!发射事件成功!请注意接收。【下面是父组件接收事件的代码】

<div class="warp">
    <cnp :number1="num1" :number2="num2" 
        @num1change='numchange1' 
        @num2change='numchange2'/>
</div>

  接收成功!!接收成功!!正在紧急处理中...【下面是父组件对事件的处理】

methods:{
    numchange1(value){
        this.num1=value
    },
    numchange2(value){
        this.num2=value
    }
}
//注意哦!这个是Vue中的methods,不是component的methods

好了,万事俱备只欠东风!让我们一起嗨起来吧!

子传父.gif

成功了!小编简直就是天使!
image.png

诶?!不对,又有错!!!!!
image.png

  好吧,我知道你们看不懂,这次小编真的没有查百度,完全是靠着智慧取胜的!意思就是number1在传递给value的时候发生类型错误,默认情况下value传递的是string。你还别不信,因为下面有犯罪证据:
image.png

打印的时候确实是string类型,这个时候只需要通过parseInt转换就好了

methods:{
    numchange1(value){
        this.num1=parseInt(value)
    },
    numchange2(value){
        this.num2=parseInt(value)
    }
},

到目前为止,我们已经......等等等等,小编忘记放整个代码了

    <body>
        <!-- 父组件Vue实例模板 -->
        <div class="warp">
            <!-- 如果cnp没有内容的话,可以使用单标签也就是<cnp></cnp>==><cnp/>-->
            <cnp :number1="num1" :number2="num2" 
                @num1change='numchange1' 
                @num2change='numchange2'/>
        </div>
        <!-- 子组件cnp的模板 -->
        <template id="tem">
            <div>
                <h2>props:{{number1}}</h2>
                <h2>data:{{dnumber1}}</h2>      
                <!-- v-model 的实质是v-bind 和 input事件 -->
                <!-- 将value的值动态传递给dnumber1,当输入框发生改变时,就会触发num1Input事件 -->
                <input type="text" :value='dnumber1' @input='num1Input'>
                <h2>props:{{number2}}</h2>
                <h2>data:{{dnumber2}}</h2>
                <input type="text" v-model="dnumber2" @input='num2Input'>
            </div>
        </template> 
        <script>        
            var vm = new Vue({
                el:'.warp',
                data:{
                    num1:1,
                    num2:2
                },
                methods:{
                    // 父组件接收子组件发送的时间做的处理:将子组件发送的dnumber1赋值给num1
                    numchange1(value){
                        this.num1=parseInt(value)
                    },
                    numchange2(value){
                        this.num2=parseInt(value)
                    }
                },          
                // 子组件的注册
                components:{
                    cnp:{
                        template:'#tem',
                        props:{
                            number1:Number,
                            number2:Number
                        },
                        // 用data函数替代props中要修改的数据
                        data(){
                            return{
                                dnumber1:this.number1,
                                dnumber2:this.number2
                            }                       
                        },
                        methods:{
                            num1Input(event){
                                // 将输入框的值赋值给dnumber1
                                this.dnumber1=event.target.value;
                                // 对父组件发送num1change时间的同时传递dnumber1
                                this.$emit('num1change',this.dnumber1);
                            },
                            num2Input(event){
                                this.dnumber2=event.target.value;
                                this.$emit('num2change',this.dnumber2);
                            }
                        }
                    }
                }
            })
        </script>
    </body>

  到目前为止,就是小编今天为大家分享的组件通信和双向绑定的综合案例,虽然在实际的项目开发过程中很少会碰到这个绕的传递方式
  但是你要记住!在IT行业,林子大了,什么客户都有,所有为了以后的幸福着想,现在还是得绕点路。谢谢大家的支持!
(虽然做好了没有什么人看也没有什么人点赞的准备,但是还是要精心的为你们准备每日的干货O(∩_∩)O)
❤❤祝大家好梦φ( ̄∇ ̄o)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。