简易的Vue数据响应式

117 阅读2分钟

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

Vue的官方文档中,是这样描述它的数据响应式。所以这是我们深入Vue,了解它的原理非常重要一环。目前vue2.6版本,是将javascript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter

先看一下getter和setter:

setter:
let obj3 = {
姓:"a",
名:"bb",
get 姓名(){
return this.姓 + this.名;
}
set 姓名(xxx){
 this.姓 = xxx[0]
 this.名 = xxx.substring(1)
}}
obj3.姓名 = "cdd"
console.log("打印二:" + obj2.姓名); //打印二:abb
console.log(`打印三: 姓${obj3.姓},名${obj3.名}`) //打印三:姓:c,名:dd

总结: getter 就是不加括号的函数; setter就是接受一个参数的函数 用 = xxx 这样的形式触发,来改变里面的值

再来看一下Object.defineProperty()

Object.defineProperty()第一个参数是告诉它,定义再那个对象上,第二个参数就是要定义个什么

var _xxx = 0
Object.defineProperty(obj3,"xxx",{
 get(){
return _xxx
},
 set(value){
 _xxx = value
}
})

但这里需要注意定义的xxx是不存在的所以我们不能使用,需要重新定义一个值用来传。

但是这里有一个问题,我们可以通过直接改变全局变量_xxx来改变里面的值,这不是我们想看到的,那么如何解决这个问题呢?

那就需要一个代理了

let data1 = proxy({data:{n:0}}) // 括号里面是匿名对象,所以根本无法访问

function proxy({data}){
  conost obj = {}
  Object.defineProperty(obj,"n",{
     get(){
 return data.n
}
     set(value){
 if(value<0)return
 data.n = value
}
})
return obj //这就是代理
}

但我是还是可以直接去修改内容,所以我们试着将匿名函数用对象传递

let myData5 = {n:0}
let data1 = proxy({data:myData5})
那我只要修改myData5 还是能改你的数据,这时候就不能只靠代理了,还需要监听,就算你改了也没用,我监听你

let myData5 = {n:0}
let data = proxy({data:myData5})

function proxy({data}){

let value = data.n
Object.defineProperty(data,"n",{ //这里挂载的对象就是参数data
     get(){
 return value
}
     set(newvalue){
 if(newvalue<0)return
 value = newvalue
}
})
//上面这几句,就会监听data
  conost obj = {}
  Object.defineProperty(obj,"n",{
     get(){
 return data.n
}
     set(value){
 if(value<0)return
 data.n = value
}
})
return obj //这就是代理
}

上面的方法就是把原先的数据复制一遍,再删掉用新数据来填补,这样就不能通过对象修改我的数据

我们先来看一下 Vue 到底对 data 做了什么

index.html

<body>
  <div id="app"></div>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</body>
main.js

const Vue = window.Vue

const myData = {
  n:0
}

new Vue({
  data: myData,
  template: `
    <div>{{n}}</div>
  `
}).$mount('#app')

setTimeout(() => {
  myData.n += 10
}, 0)

console.log(myData)
在myData 传给 Vue 的时候 ,数值就会发生改变

控制台

// {__ob__: we}
//     n: (...)
//     __ob__: we {value: {...}, dep: ce, vmCount: 1}
//     get n: f ()
//     set n: f (t)
//     __proto__: Object

这就是响应式,vue监听了这个数值,vue 会让 vm 成为 myData 的代理,vue 会对 myData 的所有属性进行监控,当数值发生改变的时候,vue就重新渲染

小结:

Vue会让vm成为myData的代理(proxy)

对vm的操作就相当于对myData进行的操作,我们通过this来访问vm,因为this就是vm,vm就是myData的代理,所以我们可以通过this来读取data的值。

然后再通过监听来对myData的所有属性进行监控,当myData的属性改变,就能调用render(data)渲染ui,这就是响应式

Vue 的 Data 的 bug

1、如果有多个key,需要提前声明

2、Vue.set(){} / this.$set(){}可以添加data数据

数据响应式 响应式即对外界的变化做出的反应的一种形式。 const vm = new Vue({data:{n: 0}}) 当修改 vm.n 或 data.n 时,render(data...) 中的 n 就会做出响应的响应。 这个联动的过程就是 vue 的 数据响应式。