组件化mvvm
- 新旧组件化方式对比:新方法不用手动操作dom,将重心放在业务层
- 数据驱动视图
- mvvm:model view viewModel
响应式
- Object.defineProperty(target,key,value)
- 监听对象(深度监听),监听数组(改写原型上的方法),更新数据setter里面也要深度监听
- 缺点:深度监听一次迭代到底计算量大
vdom+diff
-
为什么需要vdom:减少更新范围,只更新变化的部分。
-
vnode结构:target标签 children子节点 text文本节点 data属性
-
snabbdom库使用:
- h()返回vnode
- patch(vnode,newVnode):diff算法入口,只触发一次,若两个vnode相同则继续比较调用patchVnode(),否则不继续,相同的条件是key sel相同
- patchVnode():比较data text children,text与children不共存,若都有children进行进一步比较
- updataChildren():比较children
- 定义四个下标,分别标识新旧vnode的开始和结束。while循环截止条件 oldStart>oldEnd&&newStart>newEnd
- 首先比较:newStart和oldStart, newEnd和oldEnd, newStart和oldEnd, newEnd和oldStart, 若值相同也就是key sel相同,调用patchVnode(), 若都有子节点调用updataChildren()
- 其次上边四种情况都没命中,拿新vnode的key遍历旧vnode若能找到相同的就看sel是否相同,符合条件后调用patchVnode()->updataChildren()。若找不到就新增。
- diff算法怎么计算最小更新范围?同层级比较,若key sel相同才继续比较
模板编译
- with语法:传入this,{}里面的值会查找this上的属性,也就是vm实例
- 模板编译为render函数,webpack打包时同vue-loader已经编译好了。
- 执行render函数生成vnode
组件渲染更新过程
- 初次渲染:解析模板为render函数,开发环境打包时候完成vue-loader。触发响应式,监听data属性getter setter。执行render函数生成vnode,通过patch(elem,vnode)将vnode挂载到根节点,完成渲染。注意:执行render函数模板编译时候就已经触发了getter,然后收集依赖触发哪个getter就watcher哪个,后续修改时候看修改的data是不是之前被watcher的data,如果是就重新触发render。
- 更新过程:修改data触发setter,保证该data值之前在getter中已经被监听。再重新执行render函数生成newVnode,再执行patch(vnode,newVnode)
- 流程图
- 异步渲染:vue组件时异步渲染,nextTick等待dom渲染完再回调,页面渲染会将data修改整合,多次data修改只会渲染一次,目的是减少dom操作次数,提高性能。
前端路由vue-router
- hash:监听window.onhashchange 修改 location.hash = "#/user" 手动修改url 浏览器前进后退
- history:监听window.popState 修改 history.pushState 手动修改url 浏览器前进后退
- 两者对比:hash适合toB 代表#号以及后面的字符,纯前端不会提交到server 。history适合toC,需要后端配置,location.pathname变化会请求server