深入VUE响应式问题与解答

VUE响应式

  • 什么是vue的响应式?

数据变化,页面也会更新

VUE响应式的意思就是这么简单,本文会以下面代码为基础,进行自问自答,深度探究。

    <div id="app">
        <div>{{ head }}</div>
        <ul>
            <li>{{ "姓名:"+ obj.name }}</li>
            <li>{{ "年龄:"+ obj.age }}</li>
            <li>{{ "性别:"+ obj.sex }}</li>
        </ul>
        <div>{{ arr }}</div>
    </div>
    var vm = new Vue({
        el: '#app',
        data: {
            head: 'hello today',
            obj: {
                name: 'ludeng',
                age: 18,
                sex: 'male'
            },
            arr: [1, 2, 3, 4]
        }
    })

我们在控制台打印vm

1.jpg

你会发现,vm里有我们在data里定义的数据!打印head数据,可以显示

2.jpg

那么,问题来了

  • 问:为什么可以直接通过vm.xxx访问data里的数据,而不是vm.data.xxx?

便于监控数据变化 实现响应式。
vm.data.xxx比vm.xxx多了一个点!😱多恐怖,主要是监控起来麻烦还多消耗性能(毕竟多一层),把所有需要监测的(不只data里,还有methods等),直接代理给vm实例,然后只监测vm,它不香吗?

好奇的同学可能被控制台的一坨$开头变量吸引了

  • 问:实例中除了data数据外,其他东西是啥子?

就是个普通变量而已,只不过为了防止名称冲突,vue会把自己内部的属性成员名称前加上$或_,如果加上的是$,代表是我们可以使用的,如果加上的是_,是vue自己内部使用的方法或属性,我们不需要调用

好了,我们继续探讨vue响应式,我提个问题,更改数据后,页面会立刻重新渲染吗?有哪位同学会,会的请举手?小明:"会"。你坐下吧,不对。

  • 问:更改数据后,页面会立刻重新渲染吗?

如果做个1000次循环,修改一个数据1000次,难道页面要重新渲染1000次?vue更新DOM的操作是异步执行的,只要侦听到数据变化,将开启一个异步队列,如果一个数据被多次变更,那么只会被推入到队列中一次,这样可以避免不必要的计算和DOM操作。

在js源代码上加两句,运行

    vm.head = "hello new day"; 
    console.log(vm.$el.innerHTML);  //相当于document.getElementById('app').innerHTML
3.jpg

页面已经变了,为什么打印出来的是原来的东西(hello today 而不是 hello new day)?

产生上面现象是还是因为vue是异步渲染,所以上面同步代码执行,打印vm.$el.innerHTML时,还未重新渲染(如果看不懂再去学习下js事件循环)

  • 问:如何在更改数据后,看到渲染后的页面上的值?

利用vm.$nextTick,在页面重新渲染,DOM更新后,会调用vm.$nextTick回调函数

    vm.head = "hello new day"; 
    console.log(vm.$el.innerHTML); 
    vm.$nextTick(()=>{
        console.log(vm.$el.innerHTML)
    })
4.jpg

执行上面代码,使用vm.$nextTick可以准确打印出

  • 问:nextTick是怎么实现的?

在nextTick的实现源码中,会先判断是否支持微任务,不支持后,才会执行宏任务
| Promise -> MutationObserver -> setImmediate -> setTimeout |依次判断是否支持,如果支持Promise,就用promise执行$nextTick,(IE)不支持就用后面的

  • 问:什么数据更改后不会渲染页面?
    1. 未被声明过(obj.aaaa)和未被渲染的数据
    2. 利用索引直接设置一个数组项/修改数组的长度时
    3. 添加或删除对象
5.jpg

如上图,修改对象会渲染页面,但添加删除对象不会,利用索引修改数组项也不会更新。最后我们打印出obj和arr,可以发现值成功修改,只是没有更新页面

  • 问:要如何响应式的更新数组和对象?
    • 更改对象
      1. 利用vm.$set(Vue.set) 增改
      2. 利用vm.$set(Vue.set) 删除
    • 更改数组:
      1. 利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse
      2. vm.$setvm.$delete(一般变异数组就够了)
  1. vm.set使用方法:vm.set(object, propertyName, value)
  2. vm.delete使用方法:vm.delete(object, target)
6.jpg

数组有更好的方法,就是使用push、pop等方法更新数据,也就是上面说的变异数组,为什么叫变异数组,因为使用它们本身使用不会重新渲染,vue进行了处理,使得调用push、pop等方法时,会渲染页面。如下图效果,页面会渲染,其他方法一样。

7.jpg
  • 但为什么上面在不使用vm.$setvm.$delete情况下,不重新渲染页面?

Object.defineProperty的锅,vue2.0利用Object.defineProperty实现响应式,下文剖析VUE响应式原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容