Vue学习—深入剖析响应式

一、响应式一

vue的响应式就是当数据变化,页面就会重新渲染。

1.怎么更改数据

<div id="app">
    {{ msg }}
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            msg: '数据修改前'
        }
    });
    setTimeout(()=>{//修改数据的方法有很多
        vm.msg = '数据修改后';
    },1000);
</script>

在这里插入图片描述
在这里插入图片描述

  • 问:为什么data会直接出现在vm实例对象中咧?

答:当创建vue实例时,vue会将data中的成员代理给vue实例,目的是为了实现响应式,监控数据变化,执行某个监听函数(怎么实现的?想一想,提示:Object.defineProperty,试着实现一下)

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

为了防止名称冲突。因为会将data中数据代理给vue,假如说我们自己写的data名称和vue中自带的属性冲突了,那么就会覆盖vue内部的属性,所以vue会把自己内部的属性成员名称前加上$或_,如果加上的是$,代表是我们可以使用的,如果加上的是_,是vue自己内部使用的方法或属性,我们不需要调用
在这里插入图片描述

  • 更改的数据必须是存在的数据,否则不能重新渲染页面,因为他监听不到,如
  <!-- 即使更改了数据,也不会重新渲染页面 -->
  <div id="app">
    {{ person.wife }} 
  </div>
  const vm = new Vue({
    el: '#app',
    data: {
      person: {
        name: 'jimo', 
        age: 18,
      }
    }
  });
  setTimeout(()=>{
        vm.person.wife = 'liu';//不会重新渲染
  },1000);

  
  • 更改的数据必须已渲染过的数据,否则从性能角度考虑,不会重新渲染页面,如:
  <!-- 即使更改了数据,也不会重新渲染页面 -->
  <div id="app">
    {{ person.age}} 
  </div>
  const vm = new Vue({
    el: '#app',
    data: {
      msg: '数据修改前',
      person: {
        name: 'jimo', 
        age: 18
      }
    }
  })
  setTimeout(()=>{
      vm.msg = '数据修改后';//页面页面没有变化
  },1000)
  • 注意
<div id="app">
    {{ msg }}
    {{ person.wife }}//刚开始未经声明
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            msg: '数据修改前',
            person: {
                name: 'jimo',
                age: 18
            }
        }
    });
    setTimeout(()=>{
        vm.person.wife = 'liu';//声明赋值
        vm.msg = '数据修改后';//渲染页面后都出现
    },1000);
</script>

在这里插入图片描述
在这里插入图片描述

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

vue更新DOM的操作是异步执行的,只要侦听到数据变化,将开启一个异步队列,如果一个数据被多次变更,那么只会被推入到队列中一次,这样可以避免不必要的计算和DOM操作。

同步执行栈执行完毕后,会执行异步队列

<div id="app">{{ msg }}</div>
const vm = new Vue({
    el: '#app',
    data: {
        msg: '数据修改前'
    }
})
vm.msg = '数据修改后';
console.log(vm.msg); // 数据修改后,此时数据已更改
console.log(vm.$el.innerHTML); // 数据修改前。此时页面还未重新渲染

在这里插入图片描述

2.vm.$el

值为被Vue控制的元素(或者说,Vue挂载的元素)
在这里插入图片描述

3.vm.$nextTick & Vue.nextTick

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

答:利用vm.$nextTickVue.nextTick,在页面重新渲染,DOM更新后,会立刻执行vm.$nextTick

<div id="app">{{ msg }}</div>
const vm = new Vue({
  el: '#app',
  data: {
    msg: '数据修改前'
  }
})
vm.msg = '数据修改后';
console.log(vm.msg); // 数据修改后,此时数据已更改
// 1. 使用vm.$nextTick
vm.$nextTick(() => {
  console.log(vm.$el.innerHTML); // 数据修改后
})
// 2. 使用Vue.nextTick
Vue.nextTick(() => {
  console.log(vm.$el.innerHTML); // 数据修改后
})
  • vm.nextTick和Vue.nextTick还可以作为Promise使用
<div id="app">{{ msg }}</div>
const vm = new Vue({
  el: '#app',
  data: {
    msg: '数据修改前'
  }
})
vm.msg = '数据修改后';
// 1. 使用vm.$nextTick
vm.$nextTick().then(() => {
  console.log(vm.$el.innerHTML); // 数据修改后
})
// 2. 使用Vue.nextTick
Vue.nextTick().then(() => {
  console.log(vm.$el.innerHTML); // 数据修改后
})
  • vm.$nextTick 和 Vue.nextTick的区别?

Vue.nextTick内部函数的this指向window

  Vue.nextTick(function () {
    console.log(this); // window
  })

vm.$nextTick内部函数的this指向Vue实例对象

  vm.$nextTick(function () {
    console.log(this); // vm实例
  })
  • 好奇nextTick是怎么实现的吗?
  • 异步任务分为宏任务(macro)和微任务(micro)
  • 前面章节已经讲过事件循环.
  • 宏任务比较慢(如setTimeout等),微任务比较快(如Promise.then()等)
  • 微任务在前,宏任务在后(eventloop,事件环)
      // 控制台打印顺序:promise > timeout
      setTimeout(() => {
        console.log('timeout');
      }, 0)  
      Promise.resolve().then(() => {
        console.log('promise');
      })
    
  • 在nextTick的实现源码中,会先判断是否支持微任务,不支持后,才会执行宏任务
      if(typeof Promise !== 'undefined') {
        // 微任务
        // 首先看一下浏览器中有没有promise
        // 因为IE浏览器中不能执行Promise
        const p = Promise.resolve();
    
      } else if(typeof MutationObserver !== 'undefined') {
        // 微任务
        // 突变观察
        // 监听文档中文字的变化,如果文字有变化,就会执行回调
        // vue的具体做法是:创建一个假节点,然后让这个假节点稍微改动一下,就会执行对应的函数
      } else if(typeof setImmediate !== 'undefined') {
        // 宏任务
        // 只在IE下有
      } else {
        // 宏任务
        // 如果上面都不能执行,那么则会调用setTimeout
      }
    
  • 曾经vue用过的宏任务:MessageChannel 消息通道 宏任务(取消了)

二、响应式二

  • 除了未被声明过和未被渲染的数据外,还有什么数据更改后不会渲染页面?

    1. 利用索引直接设置一个数组项时:

    <!-- 即使向数组中添加了第4项,数组仍然显示3项 -->
    <!-- 咳咳,一家三口,有第4个人也不能摆出来给大家看呀~ -->
    <div id="app">{{ Family }}</div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        Family: ['爸爸', '妈妈', '儿子']
      }
    })
    vm.Family[3] = '小三'; // 不是响应式的,页面不变化
    

    2. 修改数组的长度时:

    <!-- 更改了数组长度后,数组仍然显示1项 -->
    <div id="app">{{ arr }}</div>
    
    const vm = new Vue({
      el: '#app'
      data: {
        arr: ['小刘']
      }
    })
    vm.arr.length = 0; // 不是响应式的,页面不变化
    

在这里插入图片描述

3. 添加或删除对象:

<!-- 身高还是那个身高,媳妇也只有一个,不要痴心妄想 -->
<div id="app">{{ person}}</div>
const vm = new Vue({
  el: '#app'
  data: {
    person: {
      name: 'jimo',
      age: 18
    }
  }
})
vm.person.sex= 'man'; // 不是响应式的
delete vm.person.sex; // 不是响应式的
  • 问:要如何响应式的更新数组和对象?

    更改数组:

    1. 利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse
    2. 利用vm.$set/Vue.set实例方法
    3. 利用vm.$deleteVue.delete删除数组中的某一项

    vm.$setVue.set的别名
    使用方法:Vue.set(object, propertyName, value),也就是这个意思:Vue.set(要改谁,改它的什么,改成啥)

    vm.$deleteVue.delete的别名
    使用方法:Vue.delete(object, target),也就是这个意思:Vue.delete(要删除谁的值,删除哪个)

    <div id="app">{{ arr }}</div>
    
    const vm = new Vue({
      el: '#app',
      data: {
        arr: [1, 2, 3]
      }
    })
    // 使用数组变异方法
    vm.arr.push('4');
    // 使用vm.$set
    vm.$set(vm.arr, 3, 99);
    
    

在这里插入图片描述

<div id="app">{{ arr }}</div>
const vm = new Vue({
  el: '#app'
  data: {
    arr: ['小刘']
  }
})
// 更改长度时,可以用数组的splice方法
vm.dengWife.splice(100); 

更改对象:

  1. 添加利用vm.$set/Vue.set实例方法
  2. 删除利用vm.$delete/Vue.delete方法
<div id="app">{{ person }}</div>
const vm = new Vue({
  el: '#app'
  data: {
    person: {
      name: 'jimo',
      age: 18
    }
  }
})
// 添加
vm.$set(vm.person, 'sex', 'man');
// 删除
vm.$delete(vm.person, 'age')
  • 总结:

    更改数组用变异方法,就够了
    更改对象就用vm.$setvm.$delete

三、响应式原理简述

利用Object.defineProperty实现响应式的劣势

  1. 天生就需要进行递归
  2. 监听不到数组不存在的索引的改变
  3. 监听不到数组长度的改变
  4. 监听不到对象的增删
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞羽逐星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值