昨晚作了一个梦,梦见本身到了一家大厂面试,面试官走近房间,坐了下来:是杨溜溜吧?国际惯例,先来个自我介绍吧。vue
因而我巴拉巴拉开始了长达两分钟的自我介绍,与此同时,面试官边听边看个人简历,边看边皱眉,结束后问:看你以前的项目常常用到Vue,对Vue熟悉吗?node
我嘴角一笑,内心暗喜:幸亏有专门看Vue的面试题,看来此次稳了。因而谦虚又装逼的回答:还行吧,您随便问。react
因而面试官看我口气那么大,心想:哟嚯,来了一个装逼的,劳资今天就只问Vue。webpack
原文地址 欢迎stargit
Vue为MVVM框架,当数据模型data变化时,页面视图会获得响应更新,其原理对data的getter/setter方法进行拦截(Object.defineProperty或者Proxy),利用发布订阅的设计模式,在getter方法中进行订阅,在setter方法中发布通知,让全部订阅者完成响应。github
在响应式系统中,Vue会为数据模型data的每个属性新建一个订阅中心做为发布者,而监听器watch、计算属性computed、视图渲染template/render三个角色同时做为订阅者,对于监听器watch,会直接订阅观察监听的属性,对于计算属性computed和视图渲染template/render,若是内部执行获取了data的某个属性,就会执行该属性的getter方法,而后自动完成对该属性的订阅,当属性被修改时,就会执行该属性的setter方法,从而完成该属性的发布通知,通知全部订阅者进行更新。web
计算属性computed和监听器watch均可以观察属性的变化从而作出响应,不一样的是:面试
计算属性computed更可能是做为缓存功能的观察者,它能够将一个或者多个data的属性进行复杂的计算生成一个新的值,提供给渲染函数使用,当依赖的属性变化时,computed不会当即从新计算生成新的值,而是先标记为脏数据,当下次computed被获取时候,才会进行从新计算并返回。正则表达式
而监听器watch并不具有缓存性,监听器watch提供一个监听函数,当监听的属性发生变化时,会当即执行该函数。算法
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,使其同一个组件的不一样实例互不影响。
父组件 -> 子组件: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实例都是一个Event Bus,当子组件被建立的时候,父组件将事件传递给子组件,子组件初始化的时候是有$on
方法将事件注册到内部,在须要的时候使用$emit
触发函数,而对于原生native事件,使用addEventListener绑定到真实的DOM元素上。
slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素做为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。
slot又分三类,默认插槽,具名插槽和做用域插槽。
实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot
中,默认插槽为vm.$slot.default
,具名插槽为vm.$slot.xxx
,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot
中的内容进行替换,此时能够为插槽传递数据,若存在数据,则可称该插槽为做用域插槽。
vue中的模板template没法被浏览器解析并渲染,由于这不属于浏览器的标准,不是正确的HTML语法,全部须要将template转化成一个JavaScript函数,这样浏览器就能够执行这一个函数并渲染出对应的HTML元素,就可让视图跑起来了,这一个转化的过程,就成为模板编译。
模板编译又分三个阶段,解析parse,优化optimize,生成generate,最终生成可执行函数render。
对于 Vue 组件来讲,模板编译只会在组件实例化的时候编译一次,生成渲染函数以后在也不会进行编译。所以,编译对组件的 runtime 是一种性能损耗。
而模板编译的目的仅仅是将template转化为render function
,这个过程,正好能够在项目构建的过程当中完成,这样可让实际组件在 runtime 时直接跳过模板渲染,进而提高性能,这个在项目构建的编译template的过程,就是预编译。
对于 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 是 DOM 节点在 JavaScript 中的一种抽象数据结构,之因此须要虚拟DOM,是由于浏览器中操做DOM的代价比较昂贵,频繁操做DOM会产生性能问题。虚拟DOM的做用是在每一次响应式数据发生变化引发页面重渲染时,Vue对比更新先后的虚拟DOM,匹配找出尽量少的须要更新的真实DOM,从而达到提高性能的目的。
在新老虚拟DOM对比时
在diff中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从O(n^3)
下降值O(n)
,也就是说,只有当新旧children都为多个子节点时才须要用核心的Diff算法进行同层级比较。
在对节点进行diff的过程当中,判断是否为相同节点的一个很重要的条件是key是否相等,若是是相同节点,则会尽量的复用原有的DOM节点。因此key属性是提供给框架在diff的时候使用的,而非开发者。
重构响应式系统,使用Proxy替换Object.defineProperty,使用Proxy优点:
重构 Virtual DOM
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恰好解决了这两个问题。
从React Hook的实现角度看,React Hook是根据useState调用的顺序来肯定下一次重渲染时的state是来源于哪一个useState,因此出现了如下限制
而Composition API是基于Vue的响应式系统实现的,与React Hook的相比
虽然Compositon API看起来比React Hook好用,可是其设计思想也是借鉴React Hook的。
在客户端请求服务器的时候,服务器到数据库中获取到相关的数据,而且在服务器内部将Vue组件渲染成HTML,而且将数据、HTML一并返回给客户端,这个在服务器将数据和组件转化为HTML的过程,叫作服务端渲染SSR。
而当客户端拿到服务器渲染的HTML和数据以后,因为数据已经有了,客户端不须要再一次请求数据,而只须要将数据同步到组件或者Vuex内部便可。除了数据意外,HTML也结构已经有了,客户端在渲染组件的时候,也只须要将HTML的DOM节点映射到Virtual DOM便可,不须要从新建立DOM节点,这个将数据和HTML同步的过程,又叫作客户端激活。
使用SSR的好处:
更多详情查看完全理解服务端渲染 - SSR原理
面试官点了点头,嗯呢,这小伙还能够,懂得还挺多,能够弄进来写业务。
我也暗自窃喜,幸好没问到我不会的,而后我坐那傻笑,笑着笑着,忽然听到个人闹铃响了,而后,我梦醒了。
而后,新的搬砖的一天又开始了。