1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 发布订阅
class pubSub {
constructor() {
this.events = {};
}
publish(event, ...args) {
this.events[event].forEach(cb => cb(...args));
}
subscribe(event,cb) {
if(this.events[event]) {
this.events[event].push(cb);
} else {
this.events[event] = [cb];
}
}
unSubscribe(event,callback) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
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
class Vue extends EventTarget{
constructor(options) {
super();
this.$options = options;
this.compile();
this.$data = this.$options.data;
this.observe(this.$options.data);
}
async observe(data) {
if(!data || data.constructor.name !== 'Object') return;
Object.keys(data).forEach(key => {
this.defineReactive(data,key,data[key])
})
}
defineReactive(obj,key,value) {
const self = this;
this.observe(value);
Object.defineProperty(obj,key, {
enumerable: true,
configurable: true,
get() {
return value;
},
set(newValue) {
const eventName = new CustomEvent(key, {detail: {newValue}});
self.dispatchEvent(eventName);
value = newValue;
}
})
}
async compile() {
const elem = document.querySelector(this.$options.el);
const childNodes = elem.childNodes;
this.parseHtml(childNodes);
}
parseHtml(childNodes) {
[...childNodes].forEach(dom => {
if (dom.nodeType === 1) {
this.parseHtml(dom.childNodes)
} else if(dom.nodeType === 3) {
const reg = /\{\{\s*(\S+)\s*\}\}/g;
if (reg.test(dom.textContent)) {
const keys = RegExp.$1.split('.');
dom.textContent = this.$options.data[RegExp.$1];
this.addEventListener(RegExp.$1, ({detail: {newValue}}) => {
dom.textContent = newValue;
})
}
}
})
}
render() {

}
}