vue响应式原理的关键技术
1,通过Object.defineProperty()监听data中的数据变化(Observer),在vue3中使用的ES6的
proxy
2,使用发布者订阅模式,Dep(发布者)存放Watcher对象,Watcher(订阅者)
3,对html中{{}}命令进行解析(Compiler)
创建vue之后执行的操作
1, data被传入
Observer中进行key、value解析出来,使用defineProperty监听value的改变,如果改变执行Dep中的notify方法,把观察者(Watcher)全部更新,如果是获取,就把每个相对应的Watcher放入Dep.subs中
2, el会被传入Compiler中,进行命令的解析,并创建每个命令对应的Watcher
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<style>
</style>
<body>
<div id="app">
<input type="text" name="" v-model='message'>
{{message}}
</div>
<script>
class Vue {
constructor(options) {
//保存传入的数据
this.$options = options
this.$data = options.data
this.$el = options.el
//进行数据的监听改变
new Observer(this.$data,this.$el)
//进行html中{{}}解析命令
new Compiler(this.$el,this)
}
}
//data数据监听改变类
class Observer {
constructor(data,el) {
this.data = data
this.el = document.querySelector(el)
// let child = this.el.firstChild
//循环拿所有key和value
Object.keys(this.data).forEach(key => {
//进行监听
this.defineReactive(this.data,key,this.data[key])
})
}
defineReactive(data,key,val) {
const dep = new Dep()
Object.defineProperty(data,key,{
enumerable: true,
configurable: true,
set(newValue) {
if(newValue === val) {
return
}
val = newValue
dep.notify()
},
get() {
if(Dep.target) {
dep.addSub(Dep.target)
}
return val
}
})
}
}
//发布者订阅模式
class Dep {
constructor() {
this.subs = []
}
addSub(name) {
this.subs.push(name)
}
//通知所有Watcher更新数据
notify() {
this.subs.forEach(item => {
item.upData()
})
}
}
const reg = /\{\{(.+)\}\}/
//html中{{}}命令解析
class Compiler {
constructor(el,vm) {
this.el = document.querySelector(el)
this.vm = vm //指向Vue
this.flag = this._createFragment()
this.el.appendChild(this.flag)
}
_createFragment() {
//创建一个文档片段
let flag = document.createDocumentFragment()
let child
// console.log(this.el.firstChild)
while(child = this.el.firstChild) {
this._compiler(child)
flag.appendChild(child)
}
return flag
}
_compiler(node) {
//单向绑定
if(node.nodeType === 1) {
let attrs = node.attributes
if(attrs.hasOwnProperty('v-model')) {
let name = attrs['v-model'].nodeValue
node.addEventListener('input',e => {
this.vm.$data[name] = e.target.value
})
}
}
if (node.nodeType === 3) {
if(reg.test(node.nodeValue)) {
const name = RegExp.$1.trim()
new Watcher(node,name,this.vm)
}
}
}
}
//监听对象
class Watcher {
constructor(node,name,vm) {
this.node = node
this.name = name
this.vm = vm
Dep.target = this
this.upData()
}
//数据更新
upData() {
this.node.nodeValue = this.vm.$data[this.name]
}
}
const app = new Vue({
el:'#app',
data: {
message:'张三',
name:'里斯'
}
})
</script>
</body>
</html>