Vue响应式设计思路
Vue响应式主要包含:
- 数据响应式
- 监听数据变化,并在视图中更新
- Vue2使用
Object.defineProperty
实现数据劫持 - Vu3使用
Proxy
实现数据劫持 - 模板引擎
- 提供描述视图的模板语法
- 插值表达式
{ {}}
- 指令
v-bind
,v-on
,v-model
,v-for
,v-if
- 渲染
- 将模板转换为html
- 解析模板,生成
vdom
,把vdom
渲染为普通dom
数据响应式原理
数据变化时能自动更新视图,就是数据响应式
Vue2使用Object.defineProperty
实现数据变化的检测
原理解析
new Vue()
⾸先执⾏初始化,对data
执⾏响应化处理,这个过程发⽣在Observer
中- 同时对模板执⾏编译,找到其中动态绑定的数据,从
data
中获取并初始化视图,这个过程发⽣在Compile
中 - 同时定义⼀个更新函数和
Watcher实例
,将来对应数据变化时,Watcher会调⽤更新函数 - 由于
data
的某个key
在⼀个视图中可能出现多次,所以每个key
都需要⼀个管家Dep来管理多个Watcher
- 将来
data
中数据⼀旦发⽣变化,会⾸先找到对应的Dep
,通知所有Watcher
执⾏更新函数
一些关键类说明
CVue
:自定义Vue类 Observer
:执⾏数据响应化(分辨数据是对象还是数组) Compile
:编译模板,初始化视图,收集依赖(更新函数、 watcher创建) Watcher
:执⾏更新函数(更新dom) Dep
:管理多个Watcher实例,批量更新
参考 前端手写面试题详细解答
涉及关键方法说明
observe
: 遍历vm.data
的所有属性,对其所有属性做响应式,会做简易判断,创建Observer实例
进行真正响应式处理
html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cvue</title>
<script src="./cvue.js"></script>
</head>
<body>
<div id="app">
<p>{
{ count }}</p>
</div>
<script>
const app = new CVue({
el: '#app', data: {
count: 0
} }) setInterval(() => {
app.count +=1
}, 1000); </script>
</body>
</html>
CVue
- 创建基本CVue构造函数:
- 执⾏初始化,对
data
执⾏响应化处理
// 自定义Vue类
class CVue {
constructor(options) {
this.$options = options
this.$data = options.data
// 响应化处理
observe(this.$data)
}
}
// 数据响应式, 修改对象的getter,setter
function defineReactive(obj, key, val) {
// 递归处理,处理val是嵌套对象情况
observe(val)
Object.defineProperty(obj, key, {
get() {
return val
},
set(newVal) {
if(val !== newVal) {
console.log(`set ${
key}:${
newVal}, old is ${
val}`)
val = newVal
// 继续进行响应式处理,处理newVal是对象情况
observe(val)
}
}
})
}
// 遍历obj,对其所有属性做响应式
function observe(obj) {
// 只处理对象类型的
if(typeof obj !== 'object' || obj == null) {
return
}
// 实例化Observe实例
new Observe(obj)
}
// 根据传入value的类型做相应的响应式处理
class Observe {
constructor(obj) {
if(Array.isArray(obj