写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。本博客的Github地址。
[TOC]
基本使用
<!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>
<div id="container"></div>
<script src="./vue.global.js"></script>
<script>
// 获取鼠标位置,这个功能在很多地方都需要被用到
function usePositon() {
const position = Vue.reactive({x: 0, y: 0});
function update(e) {
position.x = e.pageX;
position.y = e.pageY;
}
Vue.onMounted(() => {
window.addEventListener('mousemove', update);
});
Vue.onUnmounted(() => {
window.removeEventListener('mousemove', update);
});
// toRefs将基本数据类型转为引用数据类型
return Vue.toRefs(position);
}
// composition api 多个方法进行组合来使用
const App = {
setup() { // 相当于created,只会执行一次
const state = Vue.reactive({name: 'kobe'});
const {x, y} = usePositon();
function change() {
state.name = 'james';
}
return { // 这个对象会作为渲染的上下文
state,
change,
x,
y
};
},
template: `<div @click="change">
{{state.name}}
x: {{x}}
y: {{y}}
</div>`
};
Vue.createApp().mount(App, container);
</script>
</body>
</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
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
基于Vue.reactive实现响应式数据
<script src="./vue.global.js"></script>
<script>
const proxy = Vue.reactive({name: 'kobe'});
Vue.effect(() => {
console.log(proxy.name);
});
proxy.name = 'james';
</script>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
// Vue3.0响应式原理
// Vue2.x缺陷:
// 1. 默认递归,性能不好;2. 数组改变是监听不到的;3. 对象新增的属性不能被拦截
function isObject(val) {
return typeof val === 'object' && val !== null;
}
// 1. 响应式的核心方法
function reactive(target) {
// 创建响应式对象
return createReactiveObject(target);
}
function createReactiveObject(target) {
// 如果当前不是对象,直接返回即可
if (!isObject(target)) {
return target;
}
// Reflect优势:不会报错,有返回值,将来会替代Object上的方法
const baseHandler = {
get(target, key, receiver) {
console.log('取值');
const res = Reflect.get(target, key, receiver);
if (isObject(target[key])) {
return reactive(res); // 是个递归,如果取值是一个对象的话,继续代理(主要针对多层代理的,比如对象的属性还是对象)
}
return res;
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver);
console.log('设置值');
return res;
},
deleteProperty(target, key) {
const res = Reflect.set(target, key);
console.log('删除值');
return res;
}
};
const observed = new Proxy(target, baseHandler);
return observed;
}
// 代理对象
const proxy = reactive({name: 'kobe', age: {value: 12}}); // 多层代理
// console.log(proxy.name);
// proxy.name = 'james';
proxy.age.value = 13;
// console.log(proxy.age.value);
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
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
// 核心基于proxy
// 基于Vue.reactive实现响应式数据
// Proxy兼容性差,ie11都不支持
// 创建两个哈希表
// 弱引用映射表
const toProxy = new WeakMap(); // 存放的是代理后的对象 原对象:代理过的对象
const toRaw = new WeakMap(); // 存放的是代理前的对象 代理过的对象:原对象
function trigger() {
console.log('视图更新了');
}
function isObject(target) {
return typeof target === 'object' && target !== null;
}
function reactive(target) {
// 如果目标不是对象,则不进行代理
if (!isObject(target)) {
return target;
}
// 如果代理表中已经存在了,就把这个结果返回
// 如果已经代理过了,就将代理过的结果返回即可
const proxy = toProxy.get(target);
if (proxy) {
return proxy;
}
// 如果这个对象已经被代理过了,就把对象原封不动返回
// 防止代理过的对象再次被代理
if (toRaw.has(target)) {
return target;
}
const handlers = { // 触发的方法
set(target, key, value, receiver) {
// console.log(key);
// 屏蔽掉非私有属性的更新,比如屏蔽length属性的更新
if (target.hasOwnProperty(key)) {
trigger();
}
// Reflect有返回值,是个布尔值,表示操作是否成功
return Reflect.set(target, key, value, receiver);
},
/**
* @param {*} target 源对象
* @param {*} key 对象的属性
* @param {*} receiver 代理对象
*/
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
if (isObject(target[key])) {
return reactive(res); // 是个递归,如果取值是一个对象的话,继续代理
}
return res;
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key);
}
};
// 操作代理对象的时候会触发handlers对应的方法
let observed = new Proxy(target, handlers);
toProxy.set(target, observed); // 将代理对象存储在哈希表作记录,防止重复代理
toRaw.set(observed, target);
console.log('proxy');
// 返回代理后的对象
return observed;
}
let obj = {
name: 'lisi',
arr: [1, 2, 3]
};
let p = reactive(obj);
p = reactive(obj);
p = reactive(obj);
// p.name = 'wangwu';
p.arr.push(4);
// let arr = [1, 2, 3];
// let p = reactive(arr);
// p.push(4); // 会触发length属性更新
// 原对象也发生了变化
console.log(obj); // { name: 'wangwu', arr: [ 1, 2, 3 ] }
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
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