// 如何实现简单版本的vue响应式原理
/*
响应式原理:从改变一个数据到发生改变的过程
get部分收集依赖
↓
数据改变触发set → set部分触发notify → 更改对应的虚拟dom → 更新render
*/
/*
1.构造函数(实现数据的双向绑定)
*/
/*
vue函数
vue是function,function的原型prototype是Function,
Function的原型prototype是Object
这里的Vue是构造函数
要点:实现上面的4个步骤
*/
function Vue() {
// 定义数据
this.$data = { a : 1 }
// 获取id="app"的dom元素(真实dom)
this.el = document.getElementById("app")
// 定义虚拟dom
this.virtualDom = ""
// 监听数据变化
this.observer(this.$data);
// 重新渲染
this.render()
// 构造函数,隐式创建,隐式子返回
// var this = {}
// return this
console.log(this)
}
/*
要点:vue原型prototype设置observer函数,监听数据变化(连接virtualDom,render,el,$data)
+注册getter,setter
实现12步骤,数据改变触发set+set部分触发notify(get部分收集依赖)
*/
Vue.prototype.observer = function (obj) {
var value; // 定义初始值
var self = this; // 绑定当前作用域,this = vue函数,不然没有这句,嵌套函数内再访问this,this=window
// 若$data = { a: {b:"aa"} } a为对象
// for...in...遍历对象
for (var key in obj) {
value = obj[key] //以上面为例子,obj为传入的参数this.$data,key="a",值=obj["a"]
// 判断,如果value为对象,则再调用一次observer,参数为vaule(再一次调用自身,实现访问所有数据)
if (typeof value === 'object') {
this.observer(value)
} else {
// 如果value不是对象,typeof [] === 'object(注意)
// this指向最后调用它的对象(这句话在掘金看到的,提醒要时刻记住)
Object.defineProperty(this.$data,key,{
get:function () {
// 进行依赖收集(看图即可:get部分收集依赖)
return value
},
set:function (newValue) {
// set部分通知更新(看图:set部分触发notify)
// 1.数据改变触发set → 2.set部分通知更新
value = newValue
// 4.重新render,这里要获取上层作用域,要使用self,嵌套函数内的this指向window,
self.render()
}
})
}
}
console.log(this)
}
/*
要点:实现34步骤,更改对应的虚拟dom+重新render
*/
Vue.prototype.render = function () {
// 3.更改对应的虚拟dom
this.virtualDom = 'i am ' + this.$data.a
// 4.重新render (把新的虚拟dom赋值到真实dom)
this.el.innerHTML = this.virtualDom
console.log(this) //
}
/*
2.创建实例,使用变时器setTImeout呈现效果(数据2秒后自动改变)
*/
var vm = new Vue()
setTimeout(function () {
console.log("changes")
console.log(vm.$data) // Object {a:1}
// 1. 数据改变触发set
vm.$data.a = 444
},2000)
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">
<!-- 一定要改设置:no Wrap in <body> -->
</div>
</body>
</html>