Skip to content

Commit 05f2a88

Browse files
author
Xiang Liu
committed
(vue3): stage3(refactor xxx)
1 parent e735896 commit 05f2a88

File tree

3 files changed

+124
-14
lines changed

3 files changed

+124
-14
lines changed

vue/vue3/src/dep.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
export class Dep {
4+
constructor() {
5+
this.subs = [];
6+
}
7+
8+
addSub(watcher) {
9+
this.subs.push(watcher);
10+
}
11+
}

vue/vue3/src/index.js

+27-14
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
*/
66
import {VNode} from "./vnode";
77
import {Watcher} from "./watcher";
8+
import {clearTarget, createProxy, setTarget} from "./proxy";
9+
import {Dep} from "./dep";
810

911
export class Vue3 {
1012
constructor(options) {
1113
this.$options = options;
1214
this.initProps();
13-
this.proxy = this.initDataProxy();
15+
// this.proxy = this.initDataProxy();
16+
this.proxy = createProxy(this);
1417
this.initWatcher();
1518
this.initWatch();
1619

@@ -115,13 +118,13 @@ export class Vue3 {
115118
this.collected[key] = true;
116119
}
117120

118-
if (this.$target) {
121+
/*if (this.$target) {
119122
this.$watch(key, this.$target.update.bind(this.$target));
120-
}
123+
}*/
121124
}
122125

123126
initWatcher() {
124-
this.dataNotifyChain = {};
127+
this.deps = {};
125128
}
126129

127130
initWatch() {
@@ -148,20 +151,30 @@ export class Vue3 {
148151
}
149152

150153
$watch(key, cb) {
151-
this.dataNotifyChain[key] = this.dataNotifyChain[key] || [];
152-
this.dataNotifyChain[key].push(cb);
154+
if (!this.deps[key]) {
155+
this.deps[key] = new Dep();
156+
}
157+
158+
this.deps[key].addSub(new Watcher(this.proxy, key, cb));
159+
160+
// this.dataNotifyChain[key] = this.dataNotifyChain[key] || [];
161+
// this.dataNotifyChain[key].push(cb);
153162
}
154163

155164
$mount(root) {
156-
const {mounted, render} = this.$options;
157-
158-
const vnode = render.call(this.proxy, this.createElement.bind(this));
159-
this.$el = this.createDOMElement(vnode);
160-
161-
if (root) {
162-
root.appendChild(this.$el);
163-
}
165+
this.$el = root;
166+
// const vnode = render.call(this.proxy, this.createElement.bind(this));
167+
// this.$el = this.createDOMElement(vnode);
168+
//
169+
// if (root) {
170+
// root.appendChild(this.$el);
171+
// }
172+
setTarget(this);
173+
this.update(); // first-time render and trigger 'mounted' hook
174+
clearTarget();
164175

176+
// mounted lifecycle
177+
const {mounted} = this.$options;
165178
mounted && mounted.call(this.proxy);
166179

167180
return this;

vue/vue3/src/proxy.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
let _target = null;
2+
3+
export function setTarget(target) {
4+
_target = target;
5+
}
6+
7+
export function clearTarget() {
8+
_target = null;
9+
}
10+
export function createProxy(vue) {
11+
const collect = (key) => {
12+
if (_target) {
13+
vue.$watch(key, _target.update.bind($target));
14+
}
15+
};
16+
17+
const createDataProxyHandler = (path) => {
18+
return {
19+
set: (data, key, value) => {
20+
const fullPath = path ? path + '.' + key : key;
21+
22+
const prev = data[key];
23+
data[key] = value;
24+
25+
if (prev !== value) {
26+
vue.notify(fullPath, prev, value);
27+
}
28+
29+
return true;
30+
},
31+
get: (data, key) => {
32+
const fullPath = path ? path + '.' + key : key;
33+
34+
collect(fullPath);
35+
36+
if (!!data[key] && typeof data[key] === 'object') {
37+
return new Proxy(data[key], createDataProxyHandler(fullPath));
38+
} else {
39+
return data[key];
40+
}
41+
},
42+
deleteProperty: (target, key) => {
43+
if (key in target) {
44+
const fullPath = path ? path + '.' + key : key;
45+
const pre = target[key];
46+
delete target[key];
47+
48+
this.notify(fullPath, pre);
49+
}
50+
51+
return true;
52+
}
53+
};
54+
};
55+
56+
const handler = {
57+
set: (target, key, value) => {
58+
if (key in props) { // check in props firstly
59+
return createDataProxyHandler().set(props, key, value);
60+
} else if (key in data) { // check in data secondly
61+
return createDataProxyHandler().set(data, key, value);
62+
} else {
63+
this[key] = value;
64+
}
65+
66+
return true;
67+
},
68+
get: (target, key) => {
69+
const methods = this.$options.methods || {};
70+
71+
if (key in props) {
72+
return createDataProxyHandler().get(props, key);
73+
} else if (key in data) { // 收集模板中用了 data 的属性到依赖集合中
74+
return createDataProxyHandler().get(data, key);
75+
} else if (key in computed) {
76+
return computed[key].call(this.proxy);
77+
} else if (key in methods) {
78+
return methods[key].bind(this.proxy);
79+
}
80+
81+
return this[key];
82+
},
83+
};
84+
85+
return new Proxy(this, handler);
86+
}

0 commit comments

Comments
 (0)