理解Vue的设计思想
MVVM模式
MVVM框架的三要素:数据响应式、模板引擎及其渲染
数据响应式: 监听数据变化并在视图中更新
- Object.defineProperty()
- Proxy
模板引擎: 提供描述视图的模板语法
- 插值:{{}}
- 指令:v-bind, v-on, v-model, v-for, v-if
渲染: 如何将模板转换为html
- 模板=> vdom => dom
数据响应式原理
数据变更能够响应在视图中,就是数据响应式。vue2中利用Object.defineProperty()实现变更检测。
简单实现:
const obj = {}
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`get ${key}:${val}`)
return val
},
set(newVal) {
if(newVal !== val) {
console.log(`set ${key}:${newVal}`)
val = newVal
}
}
})
}
defineReactive(obj, 'foo', 'foo')
obj.foo
obj.foo = 'fooooooooooooo'
结合视图查看效果:
<div id="app"></div>
<script>
const obj = {}
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`get ${key}:${val}`)
return val
},
set(newVal) {
if(newVal !== val) {
val = newVal
update()
}
}
})
}
defineReactive(obj, 'foo', '')
obj.foo = new Date().toLocaleTimeString()
function update() {
app.innerText = obj.foo
}
setInterval(() => {
obj.foo = new Date().toLocaleTimeString()
}, 1000)
</script>
遍历需要响应化的对象
// 对象响应化,遍历每个key,定义getter、setter
function observe(obj) {
if(typeof obj !== 'object' || obj === null) {
return
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
const obj = {foo: 'foo', bar: 'bar', baz: {a: 1}}
observe(obj)
obj.foo
obj.foo = 'fooooooo'
obj.bar
obj.bar = 'hhhhhhhhh'
obj.baz.a = 10 // 嵌套对象no ok
解决嵌套对象问题
function defineReactive(obj, key, val) {
observe(val)
Object.defineProperty(obj, key, {
//...
})
}
解决赋的值是对象的情况
obj.baz = {a:1}
obj.baz.a = 10 // no ok
set(newVal) {
if(newVal !== val) {
observe(newVal) // 新值是对象的情况
notifyUpdate()
}
}
此时,如果添加/删除了新属性依旧无法检测
obj.dong = 'dong'
obj.dong // 并没有get信息
function set(obj, key, val) {
defineReactive(obj, key, val)
}
测试:
set(obj, 'dong', 'dong')
obj.dong