zoukankan      html  css  js  c++  java
  • Vue的响应式规则

    对象属性的响应规则

    <body>
        <div id="root">
            {{msg}}
        </div>
    </body>
    <script>
        var app = new Vue({
            el:"#root",
            data:{
                msg:{
                    a:123,
                    b:{
                        k:999
                    }
                }
            }
        })
        console.log(app)
    </script>

    运行结果:

    可见,vue初始化时创建的getter/setter是递归创建的,不管这个值是否是对象,都会为这个属性创建 getter和setter 方法。有了这些getter和setter方法,直接执行:

    app.msg.b = 999;
    app.msg.a = 9990;
    app.msg['a'] = 999;
    app.msg = {xx:33};

    以上都是响应式的。

    或者直接把msg替换了也是响应式的,因为msg也有对应的getter和setter(文档中这一句:this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) 也只是变相地使用了这个规则而已),以下代码1s后在界面上显示123:

    <body>
        <div id="root">
            {{msg.a}}
        </div>
    </body>
    <script>
        new Vue({
            el:"#root",
            data:{
                msg:""
            },
            mounted:function(){
                setTimeout(()=>{
                    this.msg = {a:123}
                },1000)
            },
        });
    </script>

    对于规则:Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)。

    以上面的代码为例,不允许动态创建与msg同级别的属性。但可以通过set往msg中动态添加属性:

        Vue.set(app.msg,"c",998)
        Vue.set(app.msg,"d",{
            x:458
        })

    通过set添加的属性,都会被设置setter和getter,如果值是对象,则对象中的属性也会被设置getter和setter:

    数组的响应规则

    注意:数组对象是个例外,vue会为数组对象本身设置getter和setter,但不会为数组对象内的属性0,1,以及length属性设置getter和setter,假如元素为对象,则会为这个对象内的属性设置getter和setter:

    以上可以发现,要想达到响应效果,不能纯粹以一个对象的角度来看待数组,需要一些vue内置的数组函数来帮忙

     https://vuefe.cn/v2/guide/list.html#变化数组方法-Mutation-Methods

    使用Object.assign也能触发set方法,也就是说也是响应式的:

        let x = {
            set y(a){
                console.log("设置 y 的值等于" + a)
            }
        };
    
        x.y = 123; // 设置 y 的值等于123
    
        Object.assign(x,{
            y:999
        }) // 设置 y 的值等于999

     执行arr[0] = newObj;  这句代码没有响应式效果。但是利用以上Object.assign的效果,想要更新数组元素可以这么写:

    Object.assign(arr[0], newObj)。 这样能实现一次更新数组元素中的多个属性,而且是响应式的。

    踩坑记录

    组件嵌套三层,分别记为A->B->C,C是最里层。

    A异步请求数据,请求完成后,更新当前的data中的数据。意味着data中的数据会存在一个由初始值变为实际值的过程,会进行一次变化。

    A中的一次变化,也会导致B和C中分别出现一次变化。

    A主要就是请求数据,以及组装其他组件,如B。

    而B中使用了C组件,B组件中对传入的数据进行格式化(通过计算属性),后把计算属性传递给C组件

    C组件主要用于展示数据,以及维护自己内部的交互逻辑。

    以上做法首先遇到问题:

    1.C中需要修改传入的数据,如一个数组中的元素对象,发现修改后,C中界面没有根据修改后的数据而刷新

      解决:C中emit一个事件,让B在处理事件中,直接对计算属性进行修改。效果:能自动反映到C中。但传递事件太麻烦,代码繁琐。

    2.在C中创建data数据,其中直接返回B传入的计算属性。因为data属性在组件创建时只更新一次,即获取到的实际上是A传入的初始化数据,而后续再传入实际数据就接受不到了

      解决:在C中多加一个watch,监视计算属性,当计算属性发生变化时,将新的值赋值给data数据,以达到C中本地的data数据实时依据外部数据而更新,如

         props:["lArr","rArr"],
            data:function(){
                return {
                    lArrC:[],
                    rArrC:[]
                }
            },
            watch:{
              lArr:function(nV){
                  this.lArrC = nV;
              },
                rArr:function(nV){
                    this.rArrC = nV;
                }
            },

     结论:组件中的数据来源有三:data中初始化的、计算属性和父组件通过props传入的,其中只有前两种存在响应式(仅针对当前组件)


    另外一个记录:

    有A、B两个组件,A异步数据,B负责展示数据(根据A传入的数据,如一个userid,进行一次异步请求,展示请求得到的详细数据)

    因为A是异步请求的数据,所以最开始传给B的数据是默认数据,是无效的,那B该什么时候根据传入的数据来开始自己的异步请求呢?

    第一种尝试:在B中watch,监视userid,发现userid变化了,而且userid不为空时,就开始请求数据。结果:就算A组件中的userid发生了变化,B中对userid进行watch,发现没有生效。

    第二种尝试:在A中控制,当还没请求到数据时,通过v-if控制B组件不显示,当A中的异步数据到了后,再将B展示出来,这时B中的create方法会重新执行,在里面获取到传入的数据就必定是有效的了,即created中请求异步数据即可

  • 相关阅读:
    猜数字游戏
    发红包程序
    实现微信摇一摇部分功能
    计算1+1/2+1/3+....+1/100的值
    约瑟夫问题
    简易计时器
    简易学生管理系统
    文件加密解密
    分鱼问题
    分橘子问题
  • 原文地址:https://www.cnblogs.com/hellohello/p/8053219.html
Copyright © 2011-2022 走看看