vue部分知识点

Posted haimengqingyuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue部分知识点相关的知识,希望对你有一定的参考价值。

1. vue渐进式

 

  把框架分层:视图层 =》组件机制 =》 路由机制 =》 状态管理 =》 构建工具

  即可以使用最核心的视图层渲染功能来开发需求,也可以根据需求加入其他模块。

 

2. 变化侦测

 

  渲染:状态 =》DOM =》 用户界面

  vue响应式系统赋予框架重渲染的能力,主要归功于变化侦测,即检测数据的变化,当数据变化时驱动视图更新

 

3. Object的变化侦测

  Object.defineProperty将属性转换成getter/setter的形式来追踪变化,读取数据时会触发getter,修改时间时触发setter;在getter中收集有哪些依赖使用了数据,当触发setter时,通知getter

  中收集的依赖数据发生了变化;收集的依赖存储在Dep中,Dep用来收集依赖/删除依赖/向依赖发送消息;依赖,即Watcher,只有Watcher触发的getter才会收集依赖,哪个Watcher触发

  了getter,就把哪个Watcher收集到Dep中;当数据发生变化时会循环依赖列表,把所有Watcher都通知一遍;

  

  Watcher:先把自己设置到全局唯一的指定位置,如window.target,再读取数据,触发getter,在getter中从全局唯一的那个位置读取当前正则读取数据的Watcher,并把这个Watcher收集到

  Dep中;通过这种方式主动订阅数据的变化;

 

  ps:前面会侦测到数据中的某一个属性,若要侦测到所有属性,可以封装Observer类

 

  Observer类:把一个object中的所有数据转换成响应式的getter/setter,会侦测object中所有数据的变化;Data通过Observer转换成了getter/setter的形式追踪变化;外界通过Watcher读取

  数据时,会触发getter从而将Watcher添加到依赖中;当数据发生了变化,会触发setter,从而向Dep中的依赖发送通知;Watcher接收到通知后,会向外界发送通知,变化通知到外界后触

  发视图更新,也可能触发回调;

 

3. Array的变化侦测

  通过拦截器追踪Array的变化:用一个拦截器覆盖Array.prototype,之后,每使用Array原型上的方法操作数组时,其执行的都是拦截器中提供的方法,如push方法,然后在拦截器中使用

  原生Array的原型方法操作数组;

 

  拦截器:Array.prototype一样的object

  Array原型中可以改变数组自身内容的方法:push/pop/shift/unshift/splice/sort/reverse

 

  PS:Object依赖在defineReactive中的getter里使用Dep收集,每个key有一个对应的Dep列表来存储依赖(getter中收集依赖,Dep中存储依赖);Array在getter中收集依赖,在拦截器中触

  发依赖,在Observer实例上存储依赖;

 

4. 虚拟DOM

  声明式操作DOM:通过描述状态和DOM之间的映射关系,将状态渲染成视图,如Vue.js/Angular/React,当某个状态发生变化时,只更新与这个状态相关联的DOM节点;如Angular采用藏

  检查机制,React中采用虚拟DOM,Vue1.0采用细粒度的绑定(每一个绑定都会对应一个Watcher来观察状态变化,内存开销及依赖开销大,尤其是当状态被越多的节点使用),vue2.0采

  用中等力度的解决方案,引入了虚拟DOM(组件级别是一个Watcher实例,即使一个组件内多个节点使用了某个状态,也只有一个Watcher在观察这个状态的变化,状态变化时,只能通知

  到组件,组件内部通过虚拟dom进行对比与渲染)。

 

  虚拟DOM解决方式:通过状态生成一个虚拟节点树,使用虚拟节点树进行渲染,渲染之前,将当前虚拟节点树与上一次生成的虚拟节点树进行对比,只渲染不同的部分,将虚拟节点渲染

  到视图

 

  虚拟节点树即是组件树建立起来的虚拟节点vnode树;

 

  模块:描述状态与DOM之间的映射关系,模块编译得到渲染函数,渲染函数执行得到虚拟dom节点树,vnode通过patch渲染到视图;

 

  虚拟DOM在vue.js中做的事情:提供与真实dom节点相对应的虚拟dom节点vnode;新旧虚拟节点对比,更新视图(对比新旧虚拟节点是虚拟dom核心算法patch,可以判断哪些节点发生

  变化,只对发生变化节点更新视图);

  

  ps:使用虚拟节点可以避免不必要的真实dom操作,节省性能开销;Watcher粒度调到组件级别可缩减依赖数量和Watcher数量;

  

5. VNode

  Vue.js中存在VNode类,通过该类可以实例化不同类型的vnode实例,不同类型的vnode实例各自表示不同类型的dom元素;dom元素有元素节点/文本节点/注释节点,对应vnode实例中也有

  类似节点;vnode本质上是一个js对象,由VNode类实例化而来;

 

  vnode:

    节点描述对象,描述了应该怎么样去创建真实的dom节点;

    vnode和视图一一对应,js对象版本的dom;

    类型:注释节点/文本节点/元素节点/组件节点/函数式组件/克隆节点(优化静态节点和插槽节点)

  vnode创建真实dom并渲染到视图:

    首次渲染 =》先创建vnode,使用vnode生成真实dom元素,插入到页面渲染视图;

    再次渲染 =》 将上一次渲染的vnode缓存起来,将新创建的vnode与缓存的vnode作对比,基于更改的地方去修改真实的dom;

    ps:侦测策略采用中等粒度,当状态发生变化时通知到组件级别,组件内部使用虚拟dom渲染视图;若组件中一个状态变化,则整个组件需要重新渲染;

 

6. patch

   patching算法:将vnode渲染成真实dom;对比新旧vnode之间的不同,通过对比结果找出需要更新的节点进行更新,即在现有dom上进行修改来实现更新视图的目的;减少dom操作,提升

          性能;(dom执行速度不如js运算速度快;使用js运算成本替换dom操作的执行成本;)

  目的:修改dom节点,渲染视图(通过对比新旧vnode之间的差异,在现有dom上进行修改来达到渲染视图的目的)

  

  dom修改三件事:创建新增的节点;删除已废弃的节点;修改需要更新的节点;(当vnode与oldVnode不一样的时候,以vnode为准渲染视图)

   创建节点:

    当oldVnode不存在,而vnode存在时,直接使用vnode创建元素并渲染视图;

    当vnode与oldVnode完全不是同一个节点时,需要使用vnode生成真实的dom元素并插入到视图当中;

    ps:(非同一个节点,在dom中需要使用vnode创建新节点替换oldVnode对应的旧节点,将新创建的dom节点插入到旧节点旁边,并把旧节点删除)(根据vnode类型创建出对应类型的

    dom元素,然后将元素插入到视图中)

    只有三种类型的节点会被创建并插入到DOM中:元素节点(具有tag属性)---注释节点(isComment属性)---文本节点

    元素节点:调用当前环境下的createElement方法创建真实元素节点,如浏览器环境下document.createElement;将元素渲染视图调用当前环境下的appendChild方法,可以将一个元素

    插入到指定的父元素,如浏览器下parentNode.appendChild(ps:元素节点的子节点也需对应创建出来-递归,放在其下面)

    文本节点:createTextNode,如document.createTextNode

    注释节点:createComment,如document.createComment方法

    

  删除节点:当vnode中不存在,而oldVnode存在时,将其从dom中删除;removeNode   removeVnodes

  更新节点:当oldVnode和vnode是同一个节点时,通过对比找出新旧节点不一样的地方进行更新;

    1.首先判断是否是静态节点,是则跳过,静态节点只渲染一次后续不会更新;

    2.非静态节点,判断是否有text属性:21.有text属性直接调用setTextContent方法将视图中dom节点的内容改为虚拟节点的text属性的内容,如浏览器下node.textContent;

    (当心虚拟节点有文本属性且与旧虚拟节点文本属性不一样则直接将视图中的真实dom内容更改为新虚拟节点文本)  

    22.新虚拟节点没有text属性,即是元素节点,再分为是否有children节点:221.有children则又分为两种情况:旧虚拟节点是否有children:2211.如果旧虚拟节点有children

    再进行详细对比更新,更新children可能会移动或删除或新增某个子节点;2212.如果旧虚拟节点没有children,则旧虚拟节点是一个空标签或有文本的文本节点,若文本节

    点,先清空文本变成空标签,再将虚拟节点中的children依次创建成真实dom元素节点并插入到视图中的dom节点下面;222.无children情况,即新节点是个空节点,则直接

    将旧节点该删的删,达到空标签的目的;

     2211更新子节点:更新节点--新增节点--删除节点--移动节点位置

    对比两个子节点列表,首先需要循环,循环新节点列表,每循环到一个新节点,就去旧节点中找到和当前节点相同的那个旧节点,若在旧节点中找不到,说明当前子节点是

    由于状态变化新增的节点,要进行创建节点并插入到视图的操作,若找到了则进行更新操作,如果找到的旧节点的位置和新节点不同,则需要移动节点;若循环结束了,

    旧节点中还要剩余的节点则这些节点是需要删除的节点;

   

7.模板编译

  目的:生成渲染函数;

  渲染函数作用:每次执行它,就会使用当前最新的状态生成一份新的vnode(可生成vnode原因-代码字符串中有很多函数调用),然后使用这个vnode继续渲染;

  模板 =》模板编译(解析器-优化器-代码生成器) =》渲染函数   

  1.模板解析成AST; 2.遍历AST标记静态节点;3.AST生成渲染函数 

  解析器:将模板解析成AST,过滤器解析器(解析过滤器)------文本解析器-(解析带变量的文本,不带变量的纯文本需要解析)-----html解析器(解析模板,每当解析到HTML

  标签开始位置/结束位置/文本或注释时都会触发钩子函数,将相关信息通过参数传递出来),通过一条主线(监听HTML解析器,每当触发钩子时就生成一个对应的AST节点,生

  成AST之前会根据类型使用不同的方式生成不同的AST)将这些解析器组装在一起;当htnl解析器把所有模板都解析完毕则AST就生成好了;

  优化器:遍历AST,检测出所有静态子树并作标记,不需要重新渲染;避免一些无用功提升性能;

  代码生成器:将AST转换成渲染函数中的内容,即代码字符串;

  最终一个代码字符串导出外界使用时,会将代码字符串放到函数里即渲染函数;当渲染函数导出到外界时则模板编译的任务即完成了。

 

8.解析器

   将模板解析成AST;AST即是javascript中的对象用来描述一个节点,一个对象表示一个节点,对象中的属性用来保存节点所需的各种数据;(用一个对象描述的节点树即是AST)

  html解析器的作用是解析html,在解析html过程中会不断触发各种钩子函数,如开始标签钩子函数-结束标签钩子函数--文本钩子函数--注释钩子函数;

  <div><p>哈哈</p></div>

  解析器是从前往后解析的,解析到<div>会触发一个标签开始钩子函数start,解析到<p>会再次触发start;解析到哈哈文本触发文本钩子函数chars;解析到</p>触发标签结束钩子

  函数end,解析到</div>触发end,解析结束;

  可以在钩子函数中构建AST,在start钩子中构建元素类型的节点;在chars钩子中构建文本类型节点;在comment钩子函数中构建注释类型的节点;

  当html解析器不再触发钩子函数则说明所有模板都解析完毕,所有类型的节点都在钩子函数中构建完成,即AST构建完成;AST的层级关系用栈来记录,start节点入栈,end节点出栈;

  html模板解析过程即循环过程,即用html模板字符串来循环,每轮循环都从html模板中截取一字段字符串,重复此过程,直到html模板被截成一个空字符串时循环结束,解析完毕;

 

9.优化器

  作用:在AST中找到静态子树并作标记;

  静态子树:哪些在AST中拥有不会发生变化的节点;标记目的-提升性能;静态子树每次重新渲染时都不需要为其创建新节点;在虚拟dom中打补丁的过程可以跳过;

  在AST中找出所有静态节点并做上标记;在AST中找出所有静态根节点并做上标记;递归;

 

10.代码生成器

  将AST转换成渲染函数中的内容,即为代码字符串;代码字符串可以包装在函数中执行,该函数即是渲染函数;渲染函数执行了createElement则可以创建vnode;

  生成代码字符串是一个递归的过程,从顶向下依次处理每一个AST节点;

  节点有不同的类型:元素节点-文本节点-注释节点

  当字符串拼接好之后会将字符串拼在with中返回给调用者;

 

11.生命周期

  初始化阶段(new Vue()  beforeCreate  created)----模板编译阶段(created之后,beforeMount之前)----挂载阶段(beforeMount  mounted  beforeUpdate  updated)----卸载阶段(beforeDestroy  destroyed)

  初始化阶段:new Vue()到created之间的阶段,目的---在vue.js上初始化一些属性/事件及响应式数据,如props/methods/data/computed/watch/provide/inject。

  模板编译阶段:在created钩子函数与beforeMount钩子函数之间的阶段,目的---将模板渲染为渲染函数,只存在于完整版中。

  (ps:使用vue-loader或vueify时,*.vue文件内部的模板会在构建时预编译成js,所以最终打好的包里是不需要编译器的,运行时v版本即可;此时模板已经编译成了渲染函数,所以

     在生命周期中并不存在模板编译阶段。初始化阶段阶段的下一个阶段直接是挂载阶段)。

  挂载阶段:beforeMount钩子函数到mounted之间是挂载阶段,该阶段,vue.js会将实例挂载到dom上,即将模板渲染到指定的dom元素中,在挂载的过程中,vue.js会开启Watcher来

   追踪依赖的变化;在已挂载阶段,vue.js会持续追踪状态的变化,当数据发生变化时,Watcher会通知虚拟dom重新渲染视图,且在渲染视图前会触发beforeUpdate钩子韩,渲染完

  毕后会触发updated钩子函数;这个状态会持续到组件被销毁。

  卸载阶段:应用调用vm.$destroy方法,vue.js会将自身从父组件中删除,取消实例上所有依赖的追踪且移除所有的事件监听器。

 

12.指令

  v-前缀的特殊特性,其值-单个js表达式;

  职责:当表达式值改变时,将其产生的连带影响响应式的作用于DOM

  在模板解析阶段,在指令解析到AST,使用AST生成代码字符串的过程中实现某些内置指令的功能,最后在虚拟DOM渲染过程中触发自定义指令的钩子函数使其指令生效;

 

13 过滤器

  在编译阶段将过滤器编译成函数调用,串联的过滤器编译(解析-拼接字符串)后是一个嵌套的函数调用,前一个过滤器函数的执行结果是后一个过滤器函数的参数;常用过滤器功能

  如格式化文本

 

 

 

 

 

 

 

 

 

  参考 & 感谢 :深入浅出Vue.js

  

 

以上是关于vue部分知识点的主要内容,如果未能解决你的问题,请参考以下文章

自己总结的前端知识点(vue部分)

Vue2和Vue3的响应式原理

Vue2和Vue3的响应式原理

Vue2和Vue3的响应式原理

Vue 虚拟Dom 及 部分生命周期初探

Vue的相关知识点