Vue.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VUE</title>
</head>
<body>
<div id="app">
<input id="text2" v-model="name">
{
{
name}}
</div>
<script>
class MyVue {
constructor(options) {
//保存数据
this.$options = options;
this.$data = options.data;
this.$el = options.el;
//将data添加到响应式系统
new Observer(this.$data);
//代理this.$data的数据
// Object.keys(this.$data).forEach(key => {
// this._proxy(key)
// })
//处理el
new Compiler(this.$el, this)
}
// _proxy(key) {
// let that = this;
// Object.defineProperty(this.$data, key, {
// configurable: true,
// enumerable: true,
// set(newValue) {
// that.$data[key] = newValue
// },
// get() {
// return that.$data[key]
// }
// })
// }
}
class Observer {
constructor(data) {
this.data = data;
Object.keys(data).forEach(key => {
this.defineReactive(this.data, key, data[key]);
})
}
defineReactive(data, key, val) {
const dep = new Dep()
Object.defineProperty(data, key, {
enumerable: true,
configurable: true, //属性是否允许被删除
get() {
if (Dep.target) {
dep.addSub(Dep.target)
}
return val
},
set(newValue) {
if (newValue === val) {
return
}
val = newValue;
dep.notify()
}
})
}
}
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub => {
sub.update()
})
}
}
class Watcher {
constructor(node, name, vm) {
this.node = node
this.name = name
this.vm = vm
Dep.target = this
this.update()
Dep.target = null
}
update() {
this.node.nodeValue = this.vm.$data[this.name]
}
}
const reg = /\{
\{
(.*)\}\}/
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el)
this.vm = vm
this.frag = this._createFragment()
this.el.appendChild(this.frag)
}
_createFragment() {
const frag = document.createDocumentFragment()
let child;
while (child = this.el.firstChild) {
console.log('标签', child)
this._compiler(child)
frag.appendChild(child)
}
return frag
}
_compiler(node) {
console.log('标签类型', node.nodeType, node.nodeValue)
if (node.nodeType === 1) {
//标签节点
const attrs = node.attributes
if (attrs.hasOwnProperty('v-model')) {
const name = attrs['v-model'].nodeValue
node.value = this.vm.$data[name]
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)
}
}
}
}
new MyVue({
el: '#app',
data: {
name: '张三'
}
})
</script>
</body></html>
效果图: