/
index.html
130 lines (110 loc) · 2.27 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
</body>
<script>
const Observer = function(data) {
// ES5 实现方法 循环修改为每个属性添加get set
/*
for (let key in data) {
reactive(data, key);
}
return data;
*/
//ES6 proxy实行方法
return proxy(data);
}
const Dep = function() {
const self = this;
//这里可以用数组,就能实现同一个data,观察多个vue实例
this.depend = ()=>{
if (Dep.target) {
this.sub = Dep.target
}
}
this.notify = ()=>{
this.sub.update();
}
}
const Watcher = function(vm, fn) {
//这样的写法是为了把target传到dep实例里面,当然也可以不挂载到dep,但要有一个地方暂存起来
Dep.target = this;
this.update = function() {
console.log('in watcher update');
fn();
}
//初始化运行一次render函数
fn();
Dep.target = null;
}
const proxy = function(data){
const depDic = {};
return new Proxy(data, {
get:(target, property, value)=>{
depDic[property] = depDic[property] || new Dep();
if(property in target) {
console.log('in get');
depDic[property].depend();
return target[property];
}
return undefined;
},
set:(target, property, value)=>{
if (target[property] === value) {
return;
}
target[property] = value;
depDic[property].notify();
}
})
}
const reactive = function(obj, key) {
const dep = new Dep();
let val = obj[key];
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log('in get');
dep.depend();
return val;
},
set(newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify();
}
});
}
const Vue = function (options) {
this._data = options.data.call(this);
//设置data的get,set
this._data = Observer(this._data);
this.mount = (id)=>{
this.dom = document.querySelector(id);
new Watcher(this, this.render);
}
//渲染函数,这里主要是触发get方法
this.render = ()=>{
//这里vue应该会有虚拟dom的算法实现
this.dom.innerHTML = `<div>${this._data.text}</div>`;
}
}
const vue = new Vue({
data() {
return {
text: 'hello world'
};
}
})
vue.mount('#app');
vue._data.text = '123';
</script>
</html>