前言
今年注定是是动荡的一年,这一年发生了特别多的事情,父亲去世,公司欠薪,卖房,离职,所以,现在的我“无贷一身轻”!无房无车无娃,我已经没有可失去的了,此时的我就在谷底,我相信未来一定是会越来越好的。
找工作的这几个月,我对过去的工作经历做了总结,也进行了规划,这些日子不是用来荒废的,是重新审视自己的日子,每一天都很充实。一向不爱读书的我,今年也算读了几本书,所以我突发奇想,把我的读书笔记做一个分享,帮助大家简明扼要的获取到这些书籍的精华。那么就从刘博文老师的《深入浅出Vue.js》开启我在掘金的读书之旅吧!
核心笔记
1. 当状态(data)发生变化的时候,可以选择哪些方式更新dom?
- Angular使用脏检查;
- React使用虚拟dom;
- vue1.0使用细粒度的绑定
为什么使用细粒度的绑定就能让页面更新?
因为vue的变化侦测跟它们不一定,基于vue的变化莫测,在一定程度上vue是知道哪些状态发生了变化,这样就可以通过更细粒度的绑定来更新视图,并不需要比对。 缺点:每一个绑定都需要创建一个watcher,会造成内存开销以及依赖追踪的开销。
- vue2.0使用中等粒度的解决方案:使用虚拟dom + 组件级的watcher
组件级别是一个watcher实例,即便一个组件里面有10个节点绑定了某个状态,那么也只有一个watcher,当状态发生变化的时候,会通知组件,然后组件内部进行虚拟dom的比对,是一个折中的方案。 之所以能随意调整绑定的粒度,本质上还需要归功于变化侦测。 总结:虚拟dom将状态映射成视图的众多解決方案中的一种,
2. 模板转换为视图的渲染过程
3. 虚拟dom的执行过程
根据真实dom创建出虚拟节点,状态发生变化的时候,将新旧虚拟节点进行对比,然后更新视图。
- vnode本质上是一个普通的javascript对象,是从
VNode类实例化的对象,是节点的描述对象。 - 渲染视图的过程是先创建vnode,然后使用vnode生成真实的dom,然后将真实dom插入到视图中。
4. vnode类型
- vnode的类型有:注释节点、文本节点、元素节点、组件节点、函数式组件、克隆节点。 不同类型的vnode 之间其实只是属性不同,准确地说是有效属性不同。因为当使用
Vnode类创建一个vnode时,通过参数为实例设置属性时,无效的属性会默认被赋值为undefined 或false。 只有注释节点、文本节点、元素节点这三种节点才会被创建并插入到dom中。 - 克隆节点:克隆节点是将现有节点的属性复制到新节点中,让新创建的节点和被克隆节点的属性保持一致,从而实现克隆效果。它的作用是优化静态节点和插槽节点。 以静态节点为例,当组件内的某个状态发生变化后,当前组件会通过虚拟DOM重新渲染视图,静态节点因为它的内容不会改变,所以除了首次渲染需要执行渲染函数获取vnode之外,后续更新不需要执行渲染函数重新生成vnode。因此,这时就会使用创建克隆节点的方法将vnode克隆一份,使用克隆节点进行渲染。这样就不需要重新执行渲染函数生成新的静态节点的vnode,从而提升一定程度的性能。
克隆节点和被克隆节点之间的唯一区别是
isCloned属性,克隆节点的isCloned为true, 被克隆的原始节点的isCloned为false。 - 元素节点:通常会有4种有效属性:
tag,data(即属性,class,attrs,style),children,context(当前组件的vue.js实例) - 注释节点有效属性:
isComment,可以通过这个属性来区分注释节点和文本节点。 - 组件节点与元素节点类似,有两个特有的属性:
componentOptions,componentInstance。 - 函数式组件与组件节点类似,有两个独有的属性:
functionalcontext,functionalOptions。
5. patch
虚拟dom最核心的部分是patch(补丁、修补的意思),也可以叫做patching算法,它可以对比新旧两个vnode的区别,然后找出需要更新的节点进行更新,并渲染为真实的dom。
本质是使用Javaseript 的运算成本来替换DOM操作的执行成本。
整个patch的过程:
当oldVnode不存在时,直接使用vnode 渲染视图;当oldVnode和vnode都存在但并不是同一个节点时,使用vnode创建的DOM元素替换旧的DOM元素;当oldVnode和vnode是同一个节点时,使用更详细的对比操作对真实的DOM节点进行更新。
节点从创建到插入视图的过程:创建节点(document.createElement)→ 创建元素/文本/注释节点(document.createElement,document.createTextNode,document.createComment) → 创建子节点(递归) → 插入到parentNode中(parentNode.appendChild)。