来,先介绍一下Vue的响应式零碎

Vue为MVVM框架,当数据模型data变动时,页面视图会失去响应更新,其原理对data的getter/setter办法进行拦挡(Object.defineProperty或者Proxy),利用公布订阅的设计模式,在getter办法中进行订阅,在setter办法中公布告诉,让所有订阅者实现响应。

在响应式零碎中,Vue会为数据模型data的每一个属性新建一个订阅核心作为发布者,而监听器watch、计算属性computed、视图渲染template/render三个角色同时作为订阅者,对于监听器watch,会间接订阅察看监听的属性,对于计算属性computed和视图渲染template/render,如果外部执行获取了data的某个属性,就会执行该属性的getter办法,而后主动实现对该属性的订阅,当属性被批改时,就会执行该属性的setter办法,从而实现该属性的公布告诉,告诉所有订阅者进行更新。

computed与watch的区别

计算属性computed和监听器watch都能够察看属性的变动从而做出响应,不同的是:

计算属性computed更多是作为缓存性能的观察者,它能够将一个或者多个data的属性进行简单的计算生成一个新的值,提供给渲染函数应用,当依赖的属性变动时,computed不会立刻从新计算生成新的值,而是先标记为脏数据,当下次computed被获取时候,才会进行从新计算并返回。

而监听器watch并不具备缓存性,监听器watch提供一个监听函数,当监听的属性发生变化时,会立刻执行该函数。

介绍一下Vue的生命周期

beforeCreate:是new Vue()之后触发的第一个钩子,在以后阶段data、methods、computed以及watch上的数据和办法都不能被拜访。

created:在实例创立实现后产生,以后阶段曾经实现了数据观测,也就是能够应用数据,更改数据,在这里更改数据不会触发updated函数。能够做一些初始数据的获取,在以后阶段无奈与Dom进行交互,如果非要想,能够通过vm.$nextTick来拜访Dom。

beforeMount:产生在挂载之前,在这之前template模板已导入渲染函数编译。而以后阶段虚构Dom曾经创立实现,行将开始渲染。在此时也能够对数据进行更改,不会触发updated。

mounted:在挂载实现后产生,在以后阶段,实在的Dom挂载结束,数据实现双向绑定,能够拜访到Dom节点,应用$refs属性对Dom进行操作。

beforeUpdate:产生在更新之前,也就是响应式数据产生更新,虚构dom从新渲染之前被触发,你能够在以后阶段进行更改数据,不会造成重渲染。

updated:产生在更新实现之后,以后阶段组件Dom已实现更新。要留神的是防止在此期间更改数据,因为这可能会导致有限循环的更新。

beforeDestroy:产生在实例销毁之前,在以后阶段实例齐全能够被应用,咱们能够在这时进行善后收尾工作,比方革除计时器。

destroyed:产生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也通通被销毁。

为什么组件的data必须是一个函数

一个组件可能在很多中央应用,也就是会创立很多个实例,如果data是一个对象的话,对象是援用类型,一个实例批改了data会影响到其余实例,所以data必须应用函数,为每一个实例创立一个属于本人的data,使其同一个组件的不同实例互不影响。

组件之间是怎么通信的

  • 父子组件通信

父组件 -> 子组件:prop

子组件 -> 父组件:$on/$emit

获取组件实例:应用$parent/$children$refs.xxx,获取到实例后间接获取属性数据或调用组件办法

  • 兄弟组件通信

Event Bus:每一个Vue实例都是一个Event Bus,都反对$on/$emit,能够为兄弟组件的实例之间new一个Vue实例,作为Event Bus进行通信。

Vuex:将状态和办法提取到Vuex,实现共享

  • 跨级组件通信

应用provide/inject

Event Bus:同兄弟组件Event Bus通信

Vuex:将状态和办法提取到Vuex,实现共享

Vue事件绑定原理说一下

每一个Vue实例都是一个Event Bus,当子组件被创立的时候,父组件将事件传递给子组件,子组件初始化的时候是有$on办法将事件注册到外部,在须要的时候应用$emit触发函数,而对于原生native事件,应用addEventListener绑定到实在的DOM元素上。

slot是什么?有什么作用?原理是什么?

slot又名插槽,是Vue的内容散发机制,组件外部的模板引擎应用slot元素作为承载散发内容的进口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。

slot又分三类,默认插槽,具名插槽和作用域插槽。

  • 默认插槽:又名匿名查抄,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
  • 具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件能够呈现多个具名插槽。
  • 作用域插槽:默认插槽、具名插槽的一个变体,能够是匿名插槽,也能够是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,能够将子组件外部的数据传递给父组件,让父组件依据子组件的传递过去的数据决定如何渲染该插槽。

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,寄存在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,应用$slot中的内容进行替换,此时能够为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

Vue模板渲染的原理是什么?

vue中的模板template无奈被浏览器解析并渲染,因为这不属于浏览器的规范,不是正确的HTML语法,所有须要将template转化成一个JavaScript函数,这样浏览器就能够执行这一个函数并渲染出对应的HTML元素,就能够让视图跑起来了,这一个转化的过程,就成为模板编译。

模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render。

  • parse阶段:应用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为形象语法树AST。
  • optimize阶段:遍历AST,找到其中的一些动态节点并进行标记,不便在页面重渲染的时候进行diff比拟时,间接跳过这一些动态节点,优化runtime的性能。
  • generate阶段:将最终的AST转化为render函数字符串。

template预编译是什么?

对于 Vue 组件来说,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后在也不会进行编译。因而,编译对组件的 runtime 是一种性能损耗。

而模板编译的目标仅仅是将template转化为render function,这个过程,正好能够在我的项目构建的过程中实现,这样能够让理论组件在 runtime 时间接跳过模板渲染,进而晋升性能,这个在我的项目构建的编译template的过程,就是预编译。

那template和jsx的有什么别离?

对于 runtime 来说,只须要保障组件存在 render 函数即可,而咱们有了预编译之后,咱们只须要保障构建过程中生成 render 函数就能够。

在 webpack 中,咱们应用vue-loader编译.vue文件,外部依赖的vue-template-compiler模块,在 webpack 构建过程中,将template预编译成 render 函数。

与 react 相似,在增加了jsx的语法糖解析器babel-plugin-transform-vue-jsx之后,就能够间接手写render函数。

所以,template和jsx的都是render的一种表现形式,不同的是:

JSX绝对于template而言,具备更高的灵活性,在简单的组件中,更具备劣势,而 template 尽管显得有些僵滞。然而 template 在代码构造上更合乎视图与逻辑拆散的习惯,更简略、更直观、更好保护。

说一下什么是Virtual DOM

Virtual DOM 是 DOM 节点在 JavaScript 中的一种形象数据结构,之所以须要虚构DOM,是因为浏览器中操作DOM的代价比拟低廉,频繁操作DOM会产生性能问题。虚构DOM的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue比照更新前后的虚构DOM,匹配找出尽可能少的须要更新的实在DOM,从而达到晋升性能的目标。

介绍一下Vue中的Diff算法

在新老虚构DOM比照时

  • 首先,比照节点自身,判断是否为同一节点,如果不为雷同节点,则删除该节点从新创立节点进行替换
  • 如果为雷同节点,进行patchVnode,判断如何对该节点的子节点进行解决,先判断一方有子节点一方没有子节点的状况(如果新的children没有子节点,将旧的子节点移除)
  • 比拟如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作(diff外围)。
  • 匹配时,找到雷同的子节点,递归比拟子节点

在diff中,只对同层的子节点进行比拟,放弃跨级的节点比拟,使得工夫简单从O(n^3)升高值O(n),也就是说,只有当新旧children都为多个子节点时才须要用外围的Diff算法进行同层级比拟。

key属性的作用是什么

在对节点进行diff的过程中,判断是否为雷同节点的一个很重要的条件是key是否相等,如果是雷同节点,则会尽可能的复用原有的DOM节点。所以key属性是提供给框架在diff的时候应用的,而非开发者。

说说Vue2.0和Vue3.0有什么区别

  1. 重构响应式零碎,应用Proxy替换Object.defineProperty,应用Proxy劣势:
  • 可间接监听数组类型的数据变动
  • 监听的指标为对象自身,不须要像Object.defineProperty一样遍历每个属性,有肯定的性能晋升
  • 可拦挡apply、ownKeys、has等13种办法,而Object.defineProperty不行
  • 间接实现对象属性的新增/删除
  1. 新增Composition API,更好的逻辑复用和代码组织
  2. 重构 Virtual DOM
  • 模板编译时的优化,将一些动态节点编译成常量
  • slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件
  • 模板中内联事件的提取并重用(本来每次渲染都从新生成内联函数)
  1. 代码结构调整,更便于Tree shaking,使得体积更小
  2. 应用Typescript替换Flow

为什么要新增Composition API,它能解决什么问题

Vue2.0中,随着性能的减少,组件变得越来越简单,越来越难保护,而难以保护的根本原因是Vue的API设计迫使开发者应用watch,computed,methods选项组织代码,而不是理论的业务逻辑。

另外Vue2.0短少一种较为简洁的低成本的机制来实现逻辑复用,尽管能够minxis实现逻辑复用,然而当mixin变多的时候,会使得难以找到对应的data、computed或者method来源于哪个mixin,使得类型推断难以进行。

所以Composition API的呈现,次要是也是为了解决Option API带来的问题,第一个是代码组织问题,Compostion API能够让开发者依据业务逻辑组织本人的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他本人写的代码时,他能够更好的利用代码的组织反推出理论的业务逻辑,或者依据业务逻辑更好的了解代码。

第二个是实现代码的逻辑提取与复用,当然mixin也能够实现逻辑提取与复用,然而像后面所说的,多个mixin作用在同一个组件时,很难看出property是来源于哪个mixin,起源不分明,另外,多个mixin的property存在变量命名抵触的危险。而Composition API刚好解决了这两个问题。

都说Composition API与React Hook很像,说说区别

从React Hook的实现角度看,React Hook是依据useState调用的程序来确定下一次重渲染时的state是来源于哪个useState,所以呈现了以下限度

  • 不能在循环、条件、嵌套函数中调用Hook
  • 必须确保总是在你的React函数的顶层调用Hook
  • useEffect、useMemo等函数必须手动确定依赖关系

而Composition API是基于Vue的响应式零碎实现的,与React Hook的相比

  • 申明在setup函数内,一次组件实例化只调用一次setup,而React Hook每次重渲染都须要调用Hook,使得React的GC比Vue更有压力,性能也绝对于Vue来说也较慢
  • Compositon API的调用不须要顾虑调用程序,也能够在循环、条件、嵌套函数中应用
  • 响应式零碎主动实现了依赖收集,进而组件的局部的性能优化由Vue外部本人实现,而React Hook须要手动传入依赖,而且必须必须保障依赖的程序,让useEffect、useMemo等函数正确的捕捉依赖变量,否则会因为依赖不正确使得组件性能降落。

尽管Compositon API看起来比React Hook好用,然而其设计思维也是借鉴React Hook的。

SSR有理解吗?原理是什么?

在客户端申请服务器的时候,服务器到数据库中获取到相干的数据,并且在服务器外部将Vue组件渲染成HTML,并且将数据、HTML一并返回给客户端,这个在服务器将数据和组件转化为HTML的过程,叫做服务端渲染SSR。

而当客户端拿到服务器渲染的HTML和数据之后,因为数据曾经有了,客户端不须要再一次申请数据,而只须要将数据同步到组件或者Vuex外部即可。除了数据意外,HTML也构造曾经有了,客户端在渲染组件的时候,也只须要将HTML的DOM节点映射到Virtual DOM即可,不须要从新创立DOM节点,这个将数据和HTML同步的过程,又叫做客户端激活。

应用SSR的益处:

  • 有利于SEO:其实就是有利于爬虫来爬你的页面,因为局部页面爬虫是不反对执行JavaScript的,这种不反对执行JavaScript的爬虫抓取到的非SSR的页面会是一个空的HTML页面,而有了SSR当前,这些爬虫就能够获取到残缺的HTML构造的数据,进而收录到搜索引擎中。
  • 白屏工夫更短:绝对于客户端渲染,服务端渲染在浏览器申请URL之后曾经失去了一个带有数据的HTML文本,浏览器只须要解析HTML,间接构建DOM树就能够。而客户端渲染,须要先失去一个空的HTML页面,这个时候页面曾经进入白屏,之后还须要通过加载并执行 JavaScript、申请后端服务器获取数据、JavaScript 渲染页面几个过程才能够看到最初的页面。特地是在简单利用中,因为须要加载 JavaScript 脚本,越是简单的利用,须要加载的 JavaScript 脚本就越多、越大,这会导致利用的首屏加载工夫十分长,进而升高了体验感。

更多详情查看 彻底了解服务端渲染-SSR原理 https://github.com/yacan8/blo...