-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
196 lines (180 loc) · 7.21 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- V -->
<div id="demo">
{{name}}
<p>{{name}}</p>
<input v-m="name" />
<div v-h="html"></div>
<div v-f="a in arr"></div>
</div>
<script>
// 构造函数
// function Vue(obj){
// this.$el = obj.el;
// this.$data = obj.data;
// }
// class写法
class Vue {
constructor(props) {
// 数据和模板都没有
this.beforeCreated = props.beforeCreated;
this.beforeCreated()
console.log(props)
// 这个是Vue实例化的节点 Vue的作用域
let el = this.$el = document.querySelector(props.el)
// 获取实例化后,放进来的data
// 方便在后面监听所有的这些数据
let data = this.$data = props.data
// 利用发布订阅模式把M和V 数据劫持和视图编译建立关系
let watch = this.$watch = new Observer()
// 数据劫持 M
Object.keys(data).forEach((key) => {
this.proxyData(key)
})
// 视图编译 V
this.compile(el)
this.mounted = props.mounted
this.mounted()
}
// 遍历整个对象,并对所有的数据进行一次劫持
proxyData(key) {
let self = this
// 在这里Vue选择劫持整个实例化后的对象,而非this.$data
Object.defineProperty(self, key, {
// 数据一旦变动,我们触发了set的回调,视图就会发生改变
// 响应数据的改变触发对应的set和get完成对应逻辑
set(newValue) {
// 一旦值改变this.$data的值也响应改变
self.$data[key] = newValue;
console.log("值发生了更改", newValue)
// 发布者
this.$watch.emit(key, null)
},
get() {
console.log("我查看了该值")
return self.$data[key]
}
})
}
// 编译模板
// 就是把所有的el节点下的{{name}} v-for给编译解析,
// {{name}} ---》 laoyao
compile(el) {
let nodes = el.childNodes
for (let node of nodes) {
// console.log(node)
// 区分文本节点还是元素节点
switch (node.nodeType) {
// 处理元素节点
case 1:
// 判断该节点是否有v-model这个属性值
if (node.hasAttribute('v-m')) {
let attrVal = node.getAttribute('v-m')
node.value = this[attrVal]
// 监听输入事件
node.addEventListener("input", () => {
// 把v-model="name" 的 name值获取回来
// 获取输入框的值
// node.value = this[attrVal];
this[attrVal] = node.value;
// node.removeAttribute('v-m')
console.log(attrVal)
return () => {
// 更新name的值,并把值放进this.name
this[attrVal] = node.value
}
})
}else if(node.hasAttribute('v-h')){
let attrVal = node.getAttribute('v-h')
node.innerHTML = this[attrVal]
}else if(node.hasAttribute('v-f')){
let attrVal = node.getAttribute('v-h')
node.innerHTML = this[attrVal]
}
// this.compileElement(node)
// 处理文本节点
case 3:
this.compileText(node, 'textContent')
}
}
}
// 处理文本节点函数
compileText(node, type) {
let self = this;
let reg = /\{\{((?:.|\r?\n)+?)\}\}/g;
let txt = node.textContent
console.log(txt)
// 把所有的{{xxxx}}取出来xxxx
// node.textContent = this[value]
if (reg.test(txt)) {
// {{name}} -> laoyao
node.textContent = txt.replace(reg, (matched, value) => {
// 监听者,监听来自set回调函数的发布
this.$watch.on(value, () => {
node.textContent = self.$data[value]
})
console.log(matched, value)
// 监听者
return this[value]
})
}
}
}
class Observer {
constructor() {
// 空的队列
// 事件队列,发布者和订阅者的供需关系来去决定去向
this.list = {
// 'eat':[()=>{
// console.log('eat')
// }]
}
}
// 监听 订阅者
on(key, fn) {
if (!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(fn);
}
// 触发 发布者
emit(key, params) {
// 把所有存着回调函数的数组给取出来
let fns = this.list[key];
// 如果数组队列为空,则返回
if (!fns || fns.length === 0) {
return false;
}
// 如果不为空,我就遍历所有的函数执行
fns.forEach(fn => {
fn(params);
});
}
}
let vm = new Vue({
el: "#demo",
data: {
name: "lemon",
html:`<p style='color:red'>123</p>`
},
created() {
},
beforeCreated() {
},
mounted(){
console.log("挂载之后")
this.name = "laoxie"
}
})
console.log(vm)
</script>
</body>
</html>