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 的 数据响应式。