Vue响应式

深入Vue响应式

1.什么是Vue的响应式

把一个普通的JS对象,传入到Vue实例作为数据模型data选项时,当你修改它们的时候,视图会重新render。也就是说,当你修改data里面的数据的时候,视图也会变化。

//<div>{{message}}</div>
const vm = new Vue({
  data() {
    return {
      message: '初始得到渲染'
    }
  }
}).$mount('#app')

当修改为vm.message = ‘修改之后的渲染’,div中的值也会发生改变。

2.实现基本原理

基本实现是通过JS的Object.definePropety的语法来实现的。当JS对象传入到Vue实例中的时候,Vue将遍历此对象的所有数据propety,并且通过Object.definePropety内部转化为getter和setter。
通俗点说就是,Vue通过封装,监听和代理实现 数据的变化,从而实现数据重新render,即数据的实时响应。这一系列操作是Vue内部已经处理过了。
简单的封装代理监听如下所示:

// 1.创建一个代理,处理传入的对象
function proxy2({ data }) {
  let tempValue = data.n     // 用来临时存储对象中的数值
  //2. 添加一个监听,来监听初始对象中的值
  Object.defineProperty(data, 'n', {
    get() {    
       // 获取传入的对象的值
      return tempValue
    },
    set(newValue) { 
       // 修改传入对象的值
      if (newValue < 0) return
      tempValue = newValue
    }
  })
  // 以上的操作就是监听,处理你想要的数据
  let obj = {}
  Object.defineProperty(obj, 'n', {
    get() {
      // return tempValue
      return data.n
    },
    set() {
      return tempValue
    }
  })
  return obj
}
let myData2 = { n: 0 }
let obj5 = proxy2({ data: myData2 })
console.log(`需求五:${obj5.n}`)
myData2.n = -1
console.log(`需求五:${obj5.n} 设置-1失败了`)
myData2.n = 1
console.log(`需求五:${obj5.n} 设置1成功了`)
3.注意事项

由于JavaScript的限制,Vue不能监听数组和对象的响应。但是有一些方法可以来避免这个问题,让对象和数组也做到实时响应。

3.1 对于对象

对于对象,Vue是不能检测propety的添加和删除。由于在实例初始化的时候,已经对propety执行了getter和setter的转化,所以只有原型在data对象已经声明了的时候,才可以做到实时响应。

new Vue({
  data() {
    return {
      obj: {
        a: 1
      }
    }
  },
  template: `
    <div>
      <p>{{obj}}</p>
      <p>{{obj.a}}</p>
      <p>{{obj.b}}</p>
      <p>{{obj.c}}</p>
      <button @click="setObj">设置</button>
    </div>
  `,
  methods: {
    setObj() {
      // this.obj.b = 1         //页面上不会显示出b的值
      // this.$set(this.obj, 'b', 2)   // 页面上会显示出b的值
      // Vue.set(this.obj, 'b', 2)      // 页面上会显示出b的值
      // 向对象中添加多个属性
      this.obj = Object.assign({}, this.obj, { b: 2, C: 3 })      // 页面上会显示出b,c的值
      console.log(`设置以后的对象是:${JSON.stringify(this.obj)}`)
    }
  }
}).$mount('#app')

使用this.obj.b = 1,这种方法添加的属性页面响应不了,如果对象的属性没有提前声明,要做到响应,则可以使用以下两种方法

Vue.set(this.obj,'xxx',value)
this.$set(this.obj,'xxx',value)   // 此方法是全局方法Vue.set()的一个别名
//第一个参数是你要进行添加的对象
//第二个参数是你要添加的属性
//第三个属性是value

还可以向改对象中添加多个属性

this.obj = Object.assign({}, this.obj, { b: 2, C: 3 })      // 页面上会显示出b,c的值
3.2 对于数组

例如:

1.通过数组的所以直接向已有的数组中添加元素:this.tempArr[index] = value
2.直接修改数组的长度:this.tempArr.length = newLength

以上的两种操作是不能响应。

new Vue({
  data() {
    return {
        tempArr: [1, 2, 3]
    }
  },
  template: `
    <div>
      <div v-for="item in tempArr">{{item}}</div>
      <button @click="setArr">设置数组</button>
    </div>
  `,
  methods: {
    setArr() {
       // this.tempArr[3] = 4            //页面上不会显示
      // this.$set(this.tempArr, 3, 4)         //页面上会显示
      // this.tempArr.splice(0, 1)          //页面上会显示
      console.log(`改变之后的数组是:${this.tempArr}`)
    }
  }
}).$mount('#app')

对于第一种情况,也可以使用以下两种方法像数组中添加元素。

 this.$set(this.tempArr, 3, 4)         
 Vue.set(this.rempArr,3,4)      

此外,数组还有7个API,分别是

push() // 向数组中添加一个元素
pop() // 删除数组末尾的元素,数组长度减一,并且返回删除的元素
shift() // 删除数组的第一个元素,并返回删除的元素
unshift() // 向数组的开头添加一个或者多个元素,并返回新的数组长度
splice() // 向数组中添加或者删除元素,添加元素的时候,第二个参数为0,第一个参数是起始的下标
sort() // 对数组进行排序
reverse() // 颠倒数组中的元素顺序

这7个API可以做到实时响应。

4.声明响应式propety

由于 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式 property,哪怕只是一个空值:

var vm = new Vue({
  data: {
    // 声明 message 为一个空值字符串
    message: ''
  },
  template: '<div>{{ message }}</div>'
})

之后设置 message,vm.message = 'Hello!'如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问不存在的 property。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值