响应式原理

vue3 中只需要如下的代码即可实现表单联动:

1
2
3
4
5
6
7
8
9
<script>
let text = ref('default')
</script>
<template>
<div
<input v-model="text">
<p>content: {{text}} </p>
</div>
</template>

以下是一个响应式的简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
<input type="text" id="input">
<p id="content"></p>
<script>
const obj = {}
Object.defineProperty(obj, 'content', {
set(newValue){
document.getElementById('input').value = newValue
document.getElementById('content').innerHTML = newValue
}
})
document.addEventListener('keyup', e => obj.content = e.target.value)
</script>

核心是使用 Object.defineProperty 函数实现双向数据绑定,触发组件的重新渲染

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
global.__fn = null

/**
* 观察某个对象的所有属性
*/
const observe = (obj) => {
for (const k of Object.keys(obj)) {
let internalValue = obj[k]
let funs = new Set()
Object.defineProperty(obj, k, {
get(){
// 记录是哪个函数在用我 => vue 依赖收集
if (global.__fn) {
funs.add(global.__fn)
}
return internalValue
},
set(v){
internalValue = v
// 自动调用依赖该属性的函数
// 执行用过我的函数 => vue 派发更新
for (const fn of funs) {
fn()
}
}
})
}
}

const autorun = fn => {
global.__fn = fn
fn()
global.__fn = null
}

const obj = {name: 'why', age: 18}
observe(obj)
console.log(obj.name, obj.age)
autorun(() => {
console.log('重新渲染 name',obj.name)
})
autorun(() => {
console.log('重新渲染 age',obj.age)
})

obj.name = 'kobe'
obj.age = 19

console.log('------');
const o = Object.create(Object.prototype)
console.log(o);

Vue 2.0 和 3.0 的区别

  1. 移除了过滤器,推荐使用计算属性和方法。