8000 new · devazine/vue-analysis@8676fcb · GitHub
[go: up one dir, main page]

Skip to content

Commit 8676fcb

Browse files
committed
new
1 parent 9c6979c commit 8676fcb

File tree

14 files changed

+894
-2
lines changed

14 files changed

+894
-2
lines changed

1-reactive/3/reactive.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const baseHandlers = {
4343
: hasOwn(target, key);
4444

4545
const res = Reflect.set(target, key, value, receiver);
46-
trigger(target, key, hadKey ? 'set' : 'add');
46+
trigger(target, key, hadKey ? 'set' : 'add', value); // 新增传入 value 参数
4747
return res;
4848
},
4949
has(target, key) {

1-reactive/4/example.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<body>
2+
<div></div>
3+
</body>
4+
5+
<script type="module">
6+
import { setViewEffect, reactive } from './reactive.js';
7+
const div = document.querySelector('div');
8+
9+
let arr = reactive(['a', 'b', 'c']);
10+
11+
setViewEffect(() => {
12+
arr.push('d');
13+
div.innerText = arr.reduce((p, c) => (p + c))
14+
});
15+
16+
</script>

1-reactive/4/reactive.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { isObject, isArray, hasOwn, isIntegerKey } from './shared.js'
2+
3+
const proxyMap = new WeakMap();
4+
const targetMap = new WeakMap();
5+
const ITERATE_KEY = Symbol();
6+
7+
let viewEffect;
8+
9+
export const setViewEffect = (fn) => {
10+
viewEffect = fn;
11+
fn();
12+
}
13+
14+
export function reactive(target) {
15+
const existingProxy = proxyMap.get(target);
16+
if (existingProxy) {
17+
return existingProxy
18+
}
19+
20+
const proxy = new Proxy(
21+
target,
22+
baseHandlers
23+
);
24+
25+
proxyMap.set(target, proxy);
26+
return proxy
27+
}
28+
29+
// 新增,用于暂停/恢复 track 能力
30+
export let shouldTrack = true;
31+
const trackStack = [];
32+
33+
export function pauseTracking() {
34+
trackStack.push(shouldTrack)
35+
shouldTrack = false
36+
}
37+
38+
export function resetTracking() {
39+
const last = trackStack.pop()
40+
shouldTrack = last === undefined ? true : last
41+
}
42+
43+
// 新增,解决递归追踪的问题
44+
function createArrayInstrumentations(target) {
45+
const instrumentations = {};
46+
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => {
47+
instrumentations[key] = function (...args) {
48+
pauseTracking(); // 暂停 track
49+
const res = target[key].apply(this, args);
50+
resetTracking(); // 恢复 track
51+
return res
52+
}
53+
})
54+
return instrumentations
55+
}
56+
57+
const baseHandlers = {
58+
get(target, key, receiver) {
59+
// 新增,解决递归追踪的问题
60+
const targetIsArray = isArray(target);
61+
const arrayInstrumentations = createArrayInstrumentations(target);
62+
if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
63+
return Reflect.get(arrayInstrumentations, key, receiver)
64+
}
65+
66+
const res = Reflect.get(target, key, receiver);
67+
track(target, key);
68+
69+
if (isObject(res)) {
70+
return reactive(res);
71+
}
72+
73+
return res;
74+
},
75+
set(target, key, value, receiver) {
76+
const hadKey = isArray(target) && isIntegerKey(key)
77+
? Number(key) < target.length
78+
: hasOwn(target, key);
79+
80+
const res = Reflect.set(target, key, value, receiver);
81+
trigger(target, key, hadKey ? 'set' : 'add', value);
82+
return res;
83+
},
84+
has(target, key) {
85+
const res = Reflect.has(target, key);
86+
track(target, key);
87+
return res;
88+
},
89+
ownKeys(target) {
90+
const key = isArray(target) ? 'length' : ITERATE_KEY;
91+
track(target, key);
92+
return Reflect.ownKeys(target);
93+
},
94+
deleteProperty(target, key) {
95+
const hadKey = hasOwn(target, key);
96+
const res = Reflect.deleteProperty(target, key);
97+
if (res && hadKey) {
98+
trigger(target, key, 'delete');
99+
}
100+
return res
101+
}
102+
}
103+
104+
const track = (target, key) => {
105+
if (!shouldTrack || !viewEffect) return; // 新增
106+
let depsMap = targetMap.get(target)
107+
if (!depsMap) {
108+
targetMap.set(target, (depsMap = new Map()))
109+
}
110+
let dep = depsMap.get(key)
111+
if (!dep) {
112+
depsMap.set(key, (dep = new Set()));
113+
dep.add(viewEffect);
114+
}
115+
}
116+
117+
const trigger = (target, key, type, newValue) => {
118+
const depsMap = targetMap.get(target);
119+
if (!depsMap) {
120+
return
121+
}
122+
123+
let deps = [];
124+
125+
if (key === 'length' && isArray(target)) {
126+
depsMap.forEach((dep, key) => {
127+
if (key === 'length' || key >= newValue) {
128+
deps.push(dep)
129+
}
130+
})
131+
} else {
132+
if (key !== void 0) {
133+
deps.push(depsMap.get(key));
134+
}
135+
136+
switch (type) {
137+
case 'add':
138+
if (!isArray(target)) {
139+
deps.push(depsMap.get(ITERATE_KEY));
140+
} else if (isIntegerKey(key)) {
141+
deps.push(depsMap.get('length'))
142+
}
143+
break;
144+
case 'delete':
145+
if (!isArray(target)) {
146+
deps.push(depsMap.get(ITERATE_KEY));
147+
}
148+
break;
149+
}
150+
}
151+
152+
let viewEffects = [];
153+
for (const dep of deps) {
154+
if (dep) {
155+
viewEffects.push(...dep)
156+
}
157+
}
158+
159+
viewEffects = new Set(viewEffects);
160+
161+
viewEffects.forEach(effectFn => {
162+
effectFn && effectFn()
163+
});
164+
}

1-reactive/4/shared.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const isObject = val => {
2+
return val !== null && typeof val === 'object'
3+
}
4+
5+
export const isArray = Array.isArray;
6+
7+
const hasOwnProperty = Object.prototype.hasOwnProperty;
8+
export const hasOwn = (target, key) => hasOwnProperty.call(target, key);
9+
10+
export const isString = (val) => typeof val === 'string';
11+
12+
export const isIntegerKey = (key) =>
13+
isString(key) &&
14+
key !== 'NaN' &&
15+
key[0] !== '-' &&
16+
'' + parseInt(key, 10) === key

1-reactive/5/example.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<body>
2+
<div id="div-1"></div>
3+
<div id="div-2"></div>
4+
</body>
5+
6+
<script type="module">
7+
import { setViewEffect, reactive } from './reactive.js';
8+
const div1 = document.querySelector('#div-1');
9+
const div2 = document.querySelector('#div-2');
10+
11+
const obj = {a: 1};
12+
const observedObj = reactive(obj);
13+
14+
const arr = ['a', obj, 'c'];
15+
const observedArr = reactive(arr);
16+
17+
const arr2 = ['a', observedObj, 'c'];
18+
const observedArr2 = reactive(arr2);
19+
20+
div1.innerText = 'arr 中是否包含了 obj 对象:' + observedArr.includes(obj);
21+
div2.innerText += 'arr2 中是否包含了 obj 响应式对象:' + observedArr2.includes(observedObj);
22+
23+
</script>

0 commit comments

Comments
 (0)
0