Vue之数据传递

Posted hellohello

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue之数据传递相关的知识,希望对你有一定的参考价值。

基础:vue的响应式规则

简单的props更新

父组件

技术分享图片
<template>
    <div>
        <block-a :out-data="x"></block-a>
    </div>
</template>

<script>
    import blockA from ./block-a;

    export default {
        name: "App",
        components:{
            blockA
        },
        data(){
            return {
                x:123
            }
        },
        mounted(){
            setTimeout(()=>{
                this.x = 789;
            },1000)
        }
    }
</script>
View Code

子组件

技术分享图片
<template>
    <div>
        这是子组件
        {{outData}}
    </div>
</template>

<script>
    export default {
        name: "block-a",
        props:[outData],
        watch:{
            outData(newVal){
                console.log("新的值是:" + newVal)
            }
        }

    }
</script>
View Code

运行效果,界面先展示123,一秒后展示789,控制台仅输出了“新的值:789”。

结论:简单的数值类型能通过props动态反映到子组件内,而且能被子组件watch检测。

props对象的更新

父组件

技术分享图片
<template>
    <div>
        <block-a :out-data="x"></block-a>
    </div>
</template>

<script>
    import blockA from ./block-a;

    export default {
        name: "App",
        components:{
            blockA
        },
        data(){
            return {
                x:{
                    a:123,
                    b:999
                }
            }
        },
        mounted(){
            setTimeout(()=>{
                this.x.a = 789;
            },1000)
        }
    }
</script>
View Code

子组件

技术分享图片
<template>
    <div>
        这是子组件
        {{outData}}
    </div>
</template>

<script>
    export default {
        name: "block-a",
        props:[outData],
        watch:{
            outData(newVal){
                console.log("新的值是:" + newVal)
            }
        }
    }
</script>
View Code

这个例子对比上一个例子,将传递的数据改为了对象类型。对对象属性的变更,能动态反映到子组件中(子组件的界面一秒后发生正确的变化),但watch函数却没有执行(控制台无输出)。

为了监听对象属性的变化,将子组件中的watch设置修改如下:

技术分享图片
        watch:{
            outData:{
                handler(newVal){
                    console.log("新的值是:" + newVal)
                },
                deep:true
            }
        }
View Code

这样代码运行起来,不仅界面会发生变化,而且控制台也会有输出了(属性变化能被子组件watch检测到了),虽然检测出来有属性变更,却没办法知道到底是哪个属性发生了变更。

补充测试1:修改原有属性,同时添加新的属性(this.x.c=123),则子组件中检测出对象原有属性发生变更后,读取到的对象中也包含了新的属性(c=123)。

补充测试2:父组件中直接为属性赋值一个新的对象,如

技术分享图片
setTimeout(()=>{
    this.x = {
        kkk:123
    };
},1000)
View Code

则,不管子组件中采用深层watch还是普通的watch检测,都检测出变更(控制台有输出),而且界面也会发生正确变化。

补充测试3:将父组件中的响应式对象删除

技术分享图片
<template>
    <div>
        <block-a :out-data="x"></block-a>
    </div>
</template>

<script>
    import blockA from ./block-a;

    export default {
        name: "App",
        components:{
            blockA
        },
        data(){
            return {

            }
        },
        mounted(){
            setTimeout(()=>{
                this.x = {
                    kkk:123
                };
            },1000)
        }
    }
</script>
View Code

则代码运行会报错,提示渲染期间使用了x,而x未定义。而且后续子组件中没有发生任何变化,控制台也无输出。

结论:当父组件中的响应式对象通过props与子组件中的属性建立了关联后,父组件中的响应式对象发生变更(原属性发生变化和对象被重新赋值,前提是对应的setter存在,这样的赋值才是响应式的),都会通知到被关联子组件去重新渲染(与这个对象相关的属性部分dom渲染),而且watch函数会进入判断(如果是深层watch,则对比对象的属性,如果是普通watch,则简单对应对象的引用),如果没有判断出来发生变化,则不执行watch回调函数。

props对象属性的更新

以上发现一个问题,子组件能监听出对象属性发生了变化,却不知道变化了哪个属性。解决办法是使用简单watch,但是写法得改变一下,要直接定位到我关心的属性上,将子组件的watch修改如下

技术分享图片
watch:{
    [‘outData.a‘](newVal){
        console.log("新的值是:" + newVal)
    }
}
View Code

对于父组件中的x被重新赋值:新对象不存在a属性或者a属性的值与原来的值不一致时,子组件中的watch才会执行,如果重新赋值后,新对象的a属性与原对象的a属性值相同,则watch回调不执行。

结论:在上一条结论的基础上,多加一点,这个例子中的这种watch写法,仅仅是简单地再次读取对象的某个属性值(a),与原来记录的值进行对比,如果不一致,则执行watch回调。而不在乎外部的对象是否被重新赋值了,还是属性被修改了。

 

以上是关于Vue之数据传递的主要内容,如果未能解决你的问题,请参考以下文章

Vue之数据传递

将数据从底部工作表对话框片段传递到片段

vue.js之数据传递和数据分发slot

从另一个活动的活动中的片段传递数据

VUE学习笔记:10.组件化之:组件中数据的传递

使用导航从工具栏菜单项单击在片段之间传递数据 - Kotlin