共计 10758 个字符,预计需要花费 27 分钟才能阅读完成。
1、MVVM 模型
MVVM,是 Model-View-ViewModel 的简写,其本质是 MVC 模型的升级版。其中 Model 代表数据模型,View 代表看到的页面,ViewModel 是 View 和 Model 之间的桥梁,数据会绑定到 ViewModel 层并主动将数据渲染到页面中,视图变动的时候会告诉 ViewModel 层更新数据。以前是通过操作 DOM 来更新视图,当初是数据驱动视图。
2、Vue 的生命周期
Vue 的生命周期能够分为 8 个阶段:
创立前后、挂载前后、更新前后、销毁前后,以及一些非凡场景的生命周期。
Vue 3 中还新增了是 3 个用于调试和服务端渲染的场景。
Vue 2 中的生命周期钩子 | Vue 3 选项式 API 的生命周期选项 | Vue 3 组合 API 中生命周期钩子 | 形容 |
---|---|---|---|
beforeCreate | beforeCreate | setup() | 创立前,此时 data 和 methods 的数据都还没有初始化 |
created | created | setup() | 创立后,data 中有值,尚未挂载,能够进行一些 Ajax 申请 |
beforeMount | beforeMount | onBeforeMount | 挂载前,会找到虚构 DOM,编译成 Render |
mounted | mounted | onMounted | 挂载后,DOM 已创立,可用于获取拜访数据和 DOM 元素 |
beforeUpdate | beforeUpdate | onBeforeUpdate | 更新前,可用于获取更新前各种状态 |
updated | updated | onUpdated | 更新后,所有状态已是最新 |
beforeDestroy | beforeUnmount | onBeforeUnmount | 销毁前,可用于一些定时器或订阅的勾销 |
destroyed | unmounted | onUnmounted | 销毁后,可用于一些定时器或订阅的勾销 |
activated | activated | onActivated | keep-alive 缓存的组件激活时 |
deactivated | deactivated | onDeactivated | keep-alive 缓存的组件停用时 |
errorCaptured | errorCaptured | onErrorCaptured | 捕捉一个来自子孙组件的谬误时调用 |
— | renderTracked | onRenderTracked | 调试钩子,响应式依赖被收集时调用 |
— | renderTriggered | onRenderTriggered | 调试钩子,响应式依赖被触发时调用 |
— | serverPrefetch | onServerPrefetch | 组件实例在服务器上被渲染前调用 |
3、父子组件的生命周期
加载渲染阶段:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
更新阶段:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
销毁阶段:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
4、Vue.$nextTick
在下次 DOM 更新循环完结之后执行提早回调。在批改数据之后立刻应用这个办法,获取更新后的 DOM。
nextTick 是 Vue 提供的一个全局 API,因为 Vue 的异步更新策略,导致咱们对数据批改后不会间接体现在 DOM 上,此时如果想要立刻获取更新后的 DOM 状态,就须要借助该办法。Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue 将开启一个异步更新队列,并缓冲在同一事件循环中产生的所有数据变更。如果同一个 watcher 被屡次触发,只会被推入队列一次。这种在缓冲时去除反复数据对于防止不必要的计算和 DOM 操作是十分重要的。nextTick 办法会在队列中退出一个回调函数,确保该函数在后面的 DOM 操作实现后才调用。应用场景:1、如果想要在批改数据后立即失去更新后的 DOM 构造,能够应用 Vue.nextTick()
2、在 created 生命周期中进行 DOM 操作
5、Vue 实例挂载过程中产生了什么
挂载过程指的是 app.mount()过程,这是一个初始化过程,整体上做了两件事件:初始化和建设更新机制。初始化会创立组件实例、初始化组件状态、创立各种响应式数据。建设更新机制这一步会立刻执行一次组件的更新函数,这会首次执行组件渲染函数并执行 patch 将 vnode 转换为 dom;同时首次执行渲染函数会创立它外部响应式数据和组件更新函数之间的依赖关系,这使得当前数据发生变化时会执行对应的更新函数。
6、Vue 的模版编译原理
Vue 中有个独特的编译器模块,称为 compiler,它的次要作用是将用户编写的 template 编译为 js 中可执行的 render 函数。在 Vue 中,编译器会先对 template 进行解析,这一步称为 parse,完结之后失去一个 JS 对象,称之为形象语法树 AST;而后是对 AST 进行深加工的转换过程,这一步称为 transform,最初将后面失去的 AST 生成 JS 代码,也就是 render 函数。
7、Vue 的响应式原理
1、Vue 2 中的数据响应式会依据数据类型做不同的解决。如果是对象,则通过 Object.defineProperty(obj,key,descriptor)拦挡对象属性拜访,当数据被拜访或扭转时,感知并作出反应;如果是数组,则通过笼罩数组原型的办法,扩大它的 7 个变更办法(push、pop、shift、unshift、splice、sort、reverse),使这些办法能够额定的做更新告诉,从而做出响应。毛病:a、初始化时的递归遍历会造成性能损失;b、告诉更新过程须要保护大量 dep 实例和 watcher 实例,额定占用内存较多;c、新增或删除对象属性无奈拦挡,须要通过 Vue.set 及 delete 这样的 API 能力失效;d、对于 ES6 中新产生的 Map、Set 这些数据结构不反对。2、Vue 3 中利用 ES6 的 Proxy 机制代理须要响应化的数据。能够同时反对对象和数组,动静属性增、删都能够拦挡,新增数据结构均反对,对象嵌套属性运行时递归,用到时才代理,也不须要保护特地多的依赖关系,性能获得很大提高。
8、虚构 DOM
概念:虚构 DOM,顾名思义就是虚构的 DOM 对象,它自身就是一个 JS 对象,只不过是通过不同的属性去形容一个视图构造。虚构 DOM 的益处:(1) 性能晋升
间接操作 DOM 是有限度的,一个实在元素上有很多属性,如果间接对其进行操作,同时会对很多额定的属性内容进行了操作,这是没有必要的。如果将这些操作转移到 JS 对象上,就会简略很多。另外,操作 DOM 的代价是比拟低廉的,频繁的操作 DOM 容易引起页面的重绘和回流。如果通过形象 VNode 进行两头解决,能够无效缩小间接操作 DOM 次数,从而缩小页面的重绘和回流。(2) 不便跨平台实现
同一 VNode 节点能够渲染成不同平台上对应的内容,比方:渲染在浏览器是 DOM 元素节点,渲染在 Native(iOS、Android)变为对应的控件。Vue 3 中容许开发者基于 VNode 实现自定义渲染器(renderer),以便于针对不同平台进行渲染。构造:没有对立的规范,个别包含 tag、props、children 三项。tag:必选。就是标签,也能够是组件,或者函数。props:非必选。就是这个标签上的属性和办法。children:非必选。就是这个标签的内容或者子节点。如果是文本节点就是字符串;如果有子节点就是数组。换句话说,如果判断 children 是字符串的话,就示意肯定是文本节点,这个节点必定没有子元素。
9、diff 算法
概念:diff 算法是一种比照算法,通过比照旧的虚构 DOM 和新的虚构 DOM,得出是哪个虚构节点产生了扭转,找出这个虚构节点并只更新这个虚构节点所对应的实在节点,而不必更新其余未产生扭转的节点,实现精准地更新实在 DOM,进而提高效率。比照形式:diff 算法的整体策略是:深度优先,同层比拟。比拟只会在同层级进行, 不会跨层级比拟;比拟的过程中,循环从两边向两头收拢。* 首先判断两个节点的 tag 是否雷同,不同则删除该节点从新创立节点进行替换。* tag 雷同时,先替换属性,而后比照子元素,分为以下几种状况:新旧节点都有子元素时,采纳双指针形式进行比照。新旧头尾指针进行比拟,循环向两头聚拢,依据状况调用 patchVnode 进行 patch 反复流程、调用 createElem 创立一个新节点,从哈希表寻找 key 统一的 VNode 节点再分状况操作。新节点有子元素,旧节点没有子元素,则将子元素虚构节点转化成实在节点插入即可。新节点没有子元素,旧节点有子元素,则清空子元素,并设置为新节点的文本内容。新旧节点都没有子元素时,即都为文本节点,则间接比照文本内容,不同则更新。
10、Vue 中 key 的作用
key 的作用次要是为了更加高效的更新虚构 DOM。Vue 判断两个节点是否雷同时,次要是判断两者的 key 和元素类型 tag。因而,如果不设置 key,它的值就是 undefined,则可能永远认为这是两个雷同的节点,只能去做更新操作,将造成大量的 DOM 更新操作。
11、为什么组件中的 data 是一个函数
在 new Vue() 中,能够是函数也能够是对象,因为根实例只有一个,不会产生数据净化。在组件中,data 必须为函数,目标是为了避免多个组件实例对象之间共用一个 data,产生数据净化;而采纳函数的模式,initData 时会将其作为工厂函数都会返回全新的 data 对象。
12、Vue 中组件间的通信形式
父子组件通信:父向子传递数据是通过 props,子向父是通过 $emit 触发事件;通过父链 / 子链也能够通信($parent/$children);ref 也能够拜访组件实例;provide/inject;$attrs/$listeners。兄弟组件通信:全局事件总线 EventBus、Vuex。跨层级组件通信:全局事件总线 EventBus、Vuex、provide/inject。
13、v-show 和 v-if 的区别
1. 管制伎俩不同。v-show 是通过给元素增加 css 属性 display: none,但元素依然存在;而 v -if 管制元素显示或暗藏是将元素整个增加或删除。2. 编译过程不同。v-if 切换有一个部分编译 / 卸载的过程,切换过程中适合的销毁和重建外部的事件监听和子组件;v-show 只是简略的基于 css 切换。3. 编译条件不同。v-if 是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,渲染条件为假时,并不做操作,直到为真才渲染。4. 触发生命周期不同。v-show 由 false 变为 true 的时候不会触发组件的生命周期;v-if 由 false 变为 true 的时候,触发组件的 beforeCreate、created、beforeMount、mounted 钩子,由 true 变为 false 的时候触发组件的 beforeDestory、destoryed 钩子。5. 性能耗费不同。v-if 有更高的切换耗费;v-show 有更高的初始渲染耗费。应用场景:如果须要十分频繁地切换,则应用 v -show 较好,如:手风琴菜单,tab 页签等;如果在运行时条件很少扭转,则应用 v -if 较好,如:用户登录之后,依据权限不同来显示不同的内容。
14、computed 和 watch 的区别
* computed 计算属性,依赖其它属性计算值,外部任一依赖项的变动都会从新执行该函数,计算属性有缓存,多次重复应用计算属性时会从缓存中获取返回值,计算属性必须要有 return 关键词。* watch 侦听到某一数据的变动从而触发函数。当数据为对象类型时,对象中的属性值变动时须要应用深度侦听 deep 属性,也可在页面第一次加载时应用立刻侦听 immdiate 属性。使用场景:计算属性个别用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性实用于观测某个值的变动去实现一段简单的业务逻辑。
15、v-if 和 v-for 为什么不倡议放在一起应用
Vue 2 中,v-for 的优先级比 v -if 高,这意味着 v -if 将别离反复运行于每一个 v -for 循环中。如果要遍历的数组很大,而真正要展现的数据很少时,将造成很大的性能节约。Vue 3 中,则齐全相同,v-if 的优先级高于 v -for,所以 v -if 执行时,它调用的变量还不存在,会导致异样。通常有两种状况导致要这样做:* 为了过滤列表中的我的项目,比方:v-for = "user in users" v-if = "user.active"。这种状况,能够定义一个计算属性,让其返回过滤后的列表即可。* 为了防止渲染本该被暗藏的列表,比方 v -for = "user in users" v-if = "showUsersFlag"。这种状况,能够将 v -if 移至容器元素上或在外面包一层 template 即可。
16、Vue 2 中的 set 办法
set 是 Vue 2 中的一个全局 API。可手动增加响应式数据,解决数据变动视图未更新问题。当在我的项目中间接设置数组的某一项的值,或者间接设置对象的某个属性值,会发现页面并没有更新。这是因为 Object.defineProperty()的限度,监听不到数据变动,可通过 this.$set(数组或对象,数组下标或对象的属性名,更新后的值)解决。
17、keep-alive 是什么
* 作用:实现组件缓存,放弃组件的状态,防止重复渲染导致的性能问题。* 工作原理:Vue.js 外部将 DOM 节点,形象成了一个个的 VNode 节点,keep-alive 组件的缓存也是基于 VNode 节点的。它将满足条件的组件在 cache 对象中缓存起来,从新渲染的时候再将 VNode 节点从 cache 对象中取出并渲染。* 能够设置以下属性:① include:字符串或正则,只有名称匹配的组件会被缓存。② exclude:字符串或正则,任何名称匹配的组件都不会被缓存。③ max:数字,最多能够缓存多少组件实例。匹配首先查看组件的 name 选项,如果 name 选项不可用,则匹配它的部分注册名称(父组件 components 选项的键值),匿名组件不能被匹配。设置了 keep-alive 缓存的组件,会多出两个生命周期钩子:activated、deactivated。首次进入组件时:beforeCreate --> created --> beforeMount --> mounted --> activated --> beforeUpdate --> updated --> deactivated
再次进入组件时:activated --> beforeUpdate --> updated --> deactivated
18、mixin
mixin(混入),它提供了一种非常灵活的形式,来散发 Vue 组件中的可复用性能。应用场景:不同组件中常常会用到一些雷同或类似的代码,这些代码的性能绝对独立。能够通过 mixin 将雷同或类似的代码提出来。毛病:1. 变量起源不明确
2. 多 mixin 可能会造成命名抵触(解决形式:Vue 3 的组合 API)3. mixin 和组件呈现多对多的关系,使我的项目复杂度变高。
19、插槽
slot 插槽,个别在组件外部应用,封装组件时,在组件外部不确定该地位是以何种模式的元素展现时,能够通过 slot 占据这个地位,该地位的元素须要父组件以内容模式传递过去。slot 分为:* 默认插槽:子组件用 <slot> 标签来确定渲染的地位,标签外面能够放 DOM 构造作为后备内容,当父组件在应用的时候,能够间接在子组件的标签内写入内容,该局部内容将插入子组件的 <slot> 标签地位。如果父组件应用的时候没有往插槽传入内容,后备内容就会显示在页面。* 具名插槽:子组件用 name 属性来示意插槽的名字,没有指定 name 的插槽,会有隐含的名称叫做 default。父组件中在应用时在默认插槽的根底上通过 v -slot 指令指定元素须要放在哪个插槽中,v-slot 值为子组件插槽 name 属性值。应用 v -slot 指令指定元素放在哪个插槽中,必须配合 <template> 元素,且一个 <template> 元素只能对应一个预留的插槽,即不能多个 <template> 元素都应用 v -slot 指令指定雷同的插槽。v-slot 的简写是 #,例如 v -slot:header 能够简写为#header。* 作用域插槽:子组件在 <slot> 标签上绑定 props 数据,以将子组件数据传给父组件应用。父组件获取插槽绑定 props 数据的办法:1. scope="接管的变量名":<template scope="接管的变量名">
2. slot-scope="接管的变量名":<template slot-scope="接管的变量名">
3. v-slot: 插槽名 ="接管的变量名":<template v-slot: 插槽名 ="接管的变量名">
20、Vue 中的修饰符有哪些
1. 表单修饰符
lazy 填完信息,光标来到标签的时候,才会将值赋予给 value,也就是在 change 事件之后再进行信息同步。number 主动将用户输出值转化为数值类型,但如果这个值无奈被 parseFloat 解析,则会返回原来的值。trim 主动过滤用户输出的首尾空格,而两头的空格不会被过滤。2. 事件修饰符
stop 阻止了事件冒泡,相当于调用了 event.stopPropagation 办法。prevent 阻止了事件的默认行为,相当于调用了 event.preventDefault 办法。self 只当在 event.target 是以后元素本身时触发处理函数。once 绑定了事件当前只能触发一次,第二次就不会触发。capture 应用事件捕捉模式,即元素本身触发的事件先在此处解决,而后才交由外部元素进行解决。passive 通知浏览器你不想阻止事件的默认行为。native 让组件变成像 html 内置标签那样监听根元素的原生事件,否则组件上应用 v-on 只会监听自定义事件。3. 鼠标按键修饰符
left 左键点击。right 右键点击。middle 中键点击。4. 键值修饰符
键盘修饰符是用来润饰键盘事件(onkeyup,onkeydown)的,有如下:keyCode 存在很多,但 vue 为咱们提供了别名,分为以下两种:一般键(enter、tab、delete、space、esc、up...)零碎润饰键(ctrl、alt、meta、shift...)
21、对 SPA 的了解
1. 概念:SPA(Single-page application),即单页面利用,它是一种网络应用程序或网站的模型,通过动静重写以后页面来与用户交互,这种办法防止了页面之间切换时打断用户体验。在 SPA 中,所有必要的代码(HTML、JavaScript 和 CSS)都通过单个页面的加载而检索,或者依据须要(通常是响应用户操作)动静装载适当的资源并增加到页面。页面在任何工夫点都不会从新加载,也不会将管制转移到其余页面。举个例子,就像一个杯子,上午装的是牛奶,中午装的是咖啡,下午装的是茶,变得始终是内容,杯子始终不变。2. SPA 与 MPA 的区别:MPA(Muti-page application),即多页面利用。在 MPA 中,每个页面都是一个主页面,都是独立的,每当拜访一个页面时,都须要从新加载 Html、CSS、JS 文件,公共文件则依据需要按需加载。3. SPA 的优缺点:毛病:不利于搜索引擎的抓取
首次渲染速度绝对较慢
长处:具备桌面利用的即时性、网站的可移植性和可拜访性
用户体验好、快,内容的扭转不须要从新加载整个页面
良好的前后端拆散,分工更明确
22、双向绑定
1. 概念:Vue 中双向绑定是一个指令 v -model,能够绑定一个响应式数据到视图,同时视图的变动能扭转该值。v-model 是语法糖,默认状况下相当于:value 和 @input,应用 v -model 能够缩小大量繁琐的事件处理代码,进步开发效率。2. 应用:通常在表单项上应用 v -model,还能够在自定义组件上应用,示意某个值的输出和输入管制。3. 原理:v-model 是一个指令,双向绑定实际上是 Vue 的编译器实现的,通过输入蕴含 v -model 模版的组件渲染函数,实际上还是 value 属性的绑定及 input 事件监听,事件回调函数中会做相应变量的更新操作。
23、子组件是否能够间接扭转父组件的数据
1. 所有的 prop 都遵循着单项绑定准则,props 因父组件的更新而变动,天然地将新状态向上流往子组件,而不会逆向传递。这防止了子组件意外批改父组件的状态的状况,不然利用的数据流将很容易变得凌乱而难以了解。另外,每次父组件更新后,所有的子组件中的 props 都会被更新为最新值,这就意味着不应该子组件中去批改一个 prop,若这么做了,Vue 会在管制台上抛出正告。2. 理论开发过程中通常有两个场景导致要批改 prop:* prop 被用于传入初始值,而子组件想在之后将其作为一个部分数据属性。这种状况下,最好是新定义一个部分数据属性,从 props 获取初始值即可。* 须要对传入的 prop 值做进一步转换。最好是基于该 prop 值定义一个计算属性。3. 实际中,如果的确要更改父组件属性,应 emit 一个事件让父组件变更。当对象或数组作为 props 被传入时,尽管子组件无奈更改 props 绑定,但依然「能够」更改对象或数组外部的值。这是因为 JS 的对象和数组是按援用传递,而对于 Vue 来说,禁止这样的改变尽管可能,然而有很大的性能损耗,比拟得失相当。
24、Vue Router 中的罕用路由模式和原理
1. hash 模式:location.hash 的值就是 url 中 # 前面的货色。它的特点在于:hash 尽管呈现 url 中,但不会被蕴含在 HTTP 申请中,对后端齐全没有影响,因而扭转 hash 不会从新加载页面。能够为 hash 的扭转增加监听事件 window.addEventListener("hashchange", funcRef, false),每一次扭转 hash (window.location.hash),都会在浏览器的拜访历史中减少一个记录,利用 hash 的以上特点,就能够实现「前端路由更新视图但不从新申请页面」的性能了。特点:兼容性好然而不美观
2. history 模式:利用 HTML5 History Interface 中新增的 pushState()和 replaceState()办法。这两个办法利用于浏览器的历史记录栈,在以后已有的 back、forward、go 的根底上,他们提供了对历史记录进行批改的性能。这两个办法有个共同点:当调用他们批改浏览器历史记录栈后,尽管以后 url 扭转了,但浏览器不会刷新页面,这就为单页面利用前端路由“更新视图但不从新申请页面”提供了根底
特点:尽管好看,然而刷新会呈现 404 须要后端进行配置。
25、动静路由
很多时候,咱们须要将给定匹配模式的路由映射到同一个组件,这种状况就须要定义动静路由。例如,咱们有一个 User 组件,对于所有 ID 各不相同的用户,都要应用这个组件来渲染。那么,咱们能够在 vue-router 的路由门路中应用动静门路参数(dynamic segment)来达到这个成果:{path: '/user/:id', compenent: User},其中:id 就是动静门路参数。
26、对 Vuex 的了解
概念:Vuex 是 Vue 专用的状态治理库,它以全局形式集中管理利用的状态,并以相应的规定保障状态以一种可预测的形式发生变化。解决的问题:Vuex 次要解决的问题是多组件之间状态共享。利用各种通信形式,尽管也可能实现状态共享,然而往往须要在多个组件之间放弃状态的一致性,这种模式很容易出问题,也会使程序逻辑变得复杂。Vuex 通过把组件的共享状态抽取进去,以全局单例模式治理,这样任何组件都能用统一的形式获取和批改状态,响应式的数据也可能保障简洁的单向流动,使代码变得更具结构化且易于保护。什么时候用:
Vuex 并非是必须的,它可能治理状态,但同时也带来更多的概念和框架。如果咱们不打算开发大型单页利用或利用里没有大量全局的状态须要保护,齐全没有应用 Vuex 的必要,一个简略的 store 模式就够了。反之,Vuex 将是自然而然的抉择。用法:Vuex 将全局状态放入 state 对象中,它自身是一颗状态树,组件中应用 store 实例的 state 拜访这些状态;而后用配套的 mutation 办法批改这些状态,并且只能用 mutation 批改状态,在组件中调用 commit 办法提交 mutation;如果利用中有异步操作或简单逻辑组合,须要编写 action,执行完结如果有状态批改仍需提交 mutation,组件中通过 dispatch 派发 action。最初是模块化,通过 modules 选项组织拆分进来的各个子模块,在拜访状态(state)时需注意增加子模块的名称,如果子模块有设置 namespace,那么提交 mutation 和派发 action 时还须要额定的命名空间前缀。
27、页面刷新后 Vuex 状态失落怎么解决
Vuex 只是在内存中保留状态,刷新后就会失落,如果要长久化就须要保存起来。localStorage 就很适合,提交 mutation 的时候同时存入 localStorage,在 store 中把值取出来作为 state 的初始值即可。也能够应用第三方插件,举荐应用 vuex-persist 插件,它是为 Vuex 长久化贮存而生的一个插件,不须要你手动存取 storage,而是间接将状态保留至 cookie 或者 localStorage 中。
28、对于 Vue SSR 的了解
SSR 即服务端渲染(Server Side Render),就是将 Vue 在客户端把标签渲染成 html 的工作放在服务端实现,而后再把 html 间接返回给客户端。长处:有着更好的 SEO,并且首屏加载速度更快。毛病:开发条件会受限制,服务器端渲染只反对 beforeCreate 和 created 两个钩子,当咱们须要一些内部扩大库时须要非凡解决,服务端渲染应用程序也须要处于 Node.js 的运行环境。服务器会有更大的负载需要。
29、理解哪些 Vue 的性能优化办法
* 路由懒加载。无效拆分利用大小,拜访时才异步加载。* keep-alive 缓存页面。防止反复创立组件实例,且能保留缓存组件状态。* v-for 遍历防止同时应用 v -if。实际上在 Vue 3 中曾经是一个谬误用法了。* 长列表性能优化,可采纳虚构列表。* v-once。不再变动的数据应用 v -once。* 事件销毁。组件销毁后把全局变量和定时器销毁。* 图片懒加载。* 第三方插件按需引入。* 子组件宰割。较重的状态组件适宜拆分。* 服务端渲染。
正文完