vue2-原理回顾总结

114 阅读2分钟

组件化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