数据驱动视图
- 传统组件,只是静态渲染,更新还要依赖于操作DOM
- 数据驱动视图-Vue MVVM
- 数据驱动视图-React setState (暂时按下不表)
Vue MVVM(模型视图视图模型)
总结:
- 组件化
- 数据驱动视图
- MVVM
VUE的响应式
- 组件data的数据一旦变化,立即触发视图的更新
- 实现数据驱动视图的第一步
- 考察Vue原理的第一题
- 核心API-Object.defineProperty
- Object.defineProperty的缺点(vue3.0启用Proxy)
Proxy有兼容性问题
- Proxy兼容性不好,且无法polyfill
Object.defineProperty基本使用
- 监听对象,监听数组
- 复杂对象,深度监听
- 几个缺点
Object.defineProperty缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
for...in可以循环数组或对象
虚拟DOM(Virtual DOM)和diff
- vdom是实现vue和react的重要基石
- diff算法是vdom中最核心,最关键的部分
- vdom热门话题
- DOM操作非常耗费性能
- 以前用jQuery,可以自行控制DOM操作的时机,手动调整
- Vue和React是数据驱动视图,如何有效控制DOM操作
解决方案-vdom
- 有一定复杂度,减少算计次数较难
- 能不能把算计,更多的转移为JS计算?因为JS执行速度很快
- vdom-用JS模拟DOM结构,计算出最小的变更,操作DOM
用JS模拟DOM结构
通过snabbdom学习vdom
- 简洁强大的vdom库,易学易用
- Vue参考它实现的vdom和diff
- https://github.com/snabbdom/snabbdom
snabbdom重点总结
- h函数
- vnode数据结构
- patch函数
vdom总结
- 用JS模拟DOM结构(vnode)
- 新旧vnode对比,得出最小的更新范围,最后更新DOM
- 数据驱动视图的模式下,有效控制DOM操作
diff算法
- diff算法是vdom中最核心,最关键的部分
- diff算法能在日常使用vue React中体现出来(如key)
- diff算法是前端热门话题,面试宠儿
diff算法概述
- diff即对比,是一个广泛的概念,如linux diff命令,git diff等
- 两个js对象也可以做diff,如https://github.com/cujojs/jiff
- 两棵树做diff,如这里的vdom diff
树diff的时间复杂度O(n^3)
- 第一,遍历tree1;第二,遍历tree2
- 第三,排序
- 1000个节点,要计算1亿次,算法不可用
优化时间复杂度到O(n)
- 只较同一层级,不跨级比较
- tag不相同,则直接删掉重建,不再深度比较
- tag和key,两者都相同,则认为是相同节点,不在深度比较
snabbdom-源码解读(部分)
不使用key VS使用key
diff算法总结
- patchVnode
- addVnodes removeVnodes
- updateChildren(key的重要性)
vdom和diff0总结
- vdom核心概念很重要:h,vnode,patch,diff,key等
- vdom存在价值更加重要:数据驱动视图,控制DOM操作
模板编译
- 模板是vue开发中最常用的部分,基于使用相关联的原理
- html是标签语言,只有JS才能实现判断,循环
- 它不是html,有指令, 插值, js表达式,能实现判断,循环
- 会问'组件渲染和更新过程'
- 前置知识:JS的with语法
- vue template complier将模板编译为render函数
- 因此,模板一定是转换为某种JS代码,即编译模板
- 模板编译为render函数,执行render函数返回vnode
- 基于vnode在执行patch和diff
- 使用webpack vue-loader,会在开发环境下编译模板
- 执行render函数生成vnode
with语法
- 改变{}内自由变量的查找规则,当做obj属性来查找
- 如果找不到匹配的obj属性,就报错
- with要慎用.他打破了作用域规则,易读性变差
vue组件中使用render代替template
总结:
- with语法
- 模板到render函数,再到vnode,再到渲染和更新
- vue组件可以用render代替template
组件 渲染和更新 过程
- 初次渲染过程
- 更新过程
- 异步渲染
初次渲染过程
- 解析模板为render函数(或在开发环境已完成,vue-loader)
- 触发响应式,监听data属性getter setter
- 执行render函数,生成vnode,patch(elem,vnode)
执行render函数会触发getter
更新过程
- 修改data,触发setter(此前在getter中已被监听)
- 重新执行render函数,生成newVnode
- patch(vnode,newVnode)
异步渲染
- 回顾$nextTick
- 汇总data的修改,一次性更新视图
- 减少DOM操作次数,提高性能
以往知识回顾
- 响应式:监听data属性getter setter(包括数组)
- 模板编译:模板到render函数,再到vnode
- vdom:patch(elem,vnode)和patch(vnode,newVnode)
完成流程图
前端路由原理
- 稍微复杂一点的SPA,都需要路由
- vue-router也是vue全家桶的标配之一
- 属于'和日常使用相关联的原理',面试常考
- hash
- h5 history
- vue-router路由
网页url组成部分
hash的特点
- hash变化触发网页跳转.即浏览器的前进,后退
- hash变化不会刷新页面,必备的特点
- hash永远不会提交到server端
h5 history
- 用url规范大的路由,但跳转时不刷新页面
- history.pushState
- window.onpopstate
正常页面浏览
改造成h5 history模式
列子一:
总结
- hash - window.onhashchange
- H5 history - history.pushState和window.onpopstate
- H5 history需后端支持
两者选择
- to B的系统推荐用hash,简单易用,对url规范不敏感
- to C的系统,可以考虑选择H5 history,但需要服务端支持
- 能简单就简单,不用复杂
Vue原理 - 总结
- 组件化
- 响应式
- vdom和diff
- 模板编译
- 渲染过程
- 前端路由