Vue的响应式数据与非响应式数据及原理

 一.概念及使用

响应式:

  1. 当Vue组件的实例初始化的时候已有的数据就是响应式数据
  2. 通过Object.defineProperty代理实例this身上的
  3. 响应式属性的值发生改变会触发视图更新

非响应式:

  1. 当Vue组件的实例初始化的时候没有,后期添加的属性
  2. 没有通过Object.defineProperty代理实例this身上的
  3. 非响应式属性的值发生改变不会触发视图更新
  • 非响应式情况

1.直接在vm实例对象上添加属性

<template>
  <div>
    <button @click="addAttr">为vm实例添加属性</button>
    <button @click="getNoRespon">获取vm实例对象上的非响应式数据</button>
  </div>
</template>

<script>
  export default {
    name:'',
    methods:{
      addAttr(){
        this.obj={
          name:'张三' //给实例对象添加属性
        }
      },
      getNoRespon(){
        console.log(this.obj); //虽然给实例对象添加了属性,但是数据是非响应式的
      }
    }
  }
</script>

2.列表渲染通过下标更改列表中的值

需求:点击按钮更改列表中的第0号元素

<template>
  <div>
    <ul>
      <li v-for="(item,index) in arr" :key="index">{{item}}</li>
    </ul>
    <button @click="changeArr">更改0号元素</button>
  </div>
</template>

<script>
  export default {
    name:'',
    data(){
      return {
       arr:[1,2,3,4]
      }
    },
    methods:{
      //改变数组中0号元素的值
      changeArr(){
        this.arr[0]='a'
      }
    }
  }
</script>

<style scoped>
  
</style>

这种情况数据其实已经改变了,但是视图没变

 

解决方法: Vue.set || this.$set

this.arr[0]='a'
改为
this.$set(this.arr,0,'a')


或者import Vue from 'vue'
Vue.set(this.arr,0,'a')

 那么Vue数据响应式是如何实现的呢?

二.响应式底层原理

实现数据的双向绑定有几个重要的部分:

  1. 数据代理
  2. 数据劫持
  3. 模板解析

1.数据代理 =>简化对组件对象中data中属性的操作(读/写)

vm(Vue的实例对象)如果想要访问data的数据需要this._data.xxx,但是如果每个数据都这样访问太麻烦了,而Vue中是可以通过{{xxx}}或者this.xxx的形式直接访问到data中的数据,这里就使用到了数据代理

this.data.xxx => this.xxxx

数据代理原理: 

<script>
    //原先的数据
    let vm_data = {
      x: 100
    }
    //代理者->实现数据代理后直接访问代理者就能直接访问到vm_data中的数据
    let vm_self = {}

    Object.defineProperty(vm_self, 'x', {
      //读取调用
      get() {
        return vm_data.x
      },
      //修改调用
      set(value) {
        vm_data.x = value
      }
    })
    console.log(vm_self.x); //100
    console.log(vm_self.x = 200); //200
</script>

2.数据劫持 => 实现数据双向绑定

M:data

VM:在observer(一个监视函数)中,通过object.defineProperty为data中每个层次的属性重写get,set方法,并且为每个属性创建dep对象

  get:建立dep与watcher的联系

  set:数据发生改变去更新界面

V:在模板解析时,为每个节点创建watcher对象

  • this.msg='abc 
  • 由于数据代理 data.msg变成了'abc'
  • 由于数据劫持  创建dep和watcher的关系 ,通过对应的dep去通知所有的watcher去更新节点

3.模板解析

在实例化Vue时会传入一个配置对象,配置对象中包括el,data....其中el就是将对应节点传入Vue中,Vue底层进行遍历所有节点,应为节点内还会有子节点,这其中需要递归调用,遍历所有的节点属性,如果节点属性中有v-开头,那就是Vue中的指令语法,再查看节点属性有无on开头,有就是原生的指令,通过调用方法对截取的指令通过Dom2的addeventListener('事件名',{})实现是事件的绑定

<div id='app'>
    <div v-on:click='test' />
    <div onClick='test' />
</div>
//实例化Vue
new Vue({
    el:'#app',
    data(){
        return{}
    },
    methods:{test(){}}
})

 三.扩展

v-model实现数据双向绑定的本质

将data中的数据渲染到input的value上,通过input标签上的onchange方法实现data中的值改变,从而实现v-model的数据双向绑定.

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值