简介:
随着Vue在前端开发中的广泛应用,它已成为面试中的核心考点之一。为了帮助开发者在面试中更好地应对与Vue相关的问题,本文将围绕Vue面试中的高频考点进行全面梳理。
通过深入剖析这些高频面试题,你不仅能全面掌握Vue的核心概念,还能了解其在实际开发中的最佳实践,提升应对面试和项目开发的能力。这将为你在Vue领域的职业发展奠定坚实的基础。
🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
温馨提示:标题⭐越多,说明遇到的概率越大哦!
1. VUE相关---------
说说你对vue的理解⭐
vue是一个用于创建用户界面的开源Javascript框架, 也是一个创建单页面应用的web应用框架。
vue有几个核心特点:
- 数据驱动(MVVM模式)
- 组件化
Vue的优点是什么?⭐⭐
- 低耦合:视图View可以独立于Model变化和修改,一个ViewModel可以绑定到不同给的“view”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性:你可以把一些视图逻辑放在ViewModel里面,让很多view重用这段视图逻辑
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计
- 可测试:界面素来是比较难测试的,而现在测试可以针对ViewModel来写
vue3比vue2有什么优势?⭐⭐⭐
性能更好,打包体积更小,更好的ts支持,更好的代码组织,更好的逻辑抽离,更多的新功能
Vue3.0有什么更新⭐⭐⭐
-
性能优化:Vue.js 3.0使用了Proxy替代Object.defineProperty实现响应式,并且使用了静态提升技术来提高渲染性能。新增了编译时优化,在编译时进行模板静态分析,并生成更高效的渲染函数。
-
Composition API:Composition API是一个全新的组件逻辑复用方式,可以更好地组合和复用组件的逻辑。
-
TypeScript支持:Vue.js 3.0完全支持TypeScript,在编写Vue应用程序时可以更方便地利用TS的类型检查和自动补全功能。
-
新的自定义渲染API:Vue.js 3.0的自定义渲染API允许开发者在细粒度上控制组件渲染行为,包括自定义渲染器、组件事件和生命周期等。
-
改进的Vue CLI:Vue.js 3.0使用了改进的Vue CLI,可以更加灵活地配置项目,同时支持Vue.js2.x项目升级到Vue.js 3.0。
-
移除一些API:Vue.js 3.0移除了一些不常用的API,如过渡相关API,部分修饰符等。
描述Vue3生命周期⭐⭐⭐
Options API的生命周期:
beforeCreate
: 在实例初始化之后、数据观测(initState)和 event/watcher 事件配置之前被调用。 对于此时做的事情,如注册组件使用到的store或者service等单例的全局物件。 相比Vue2没有变化。created
: 一个新的 Vue 实例被创建后(包括组件实例),立即调用此函数。 在这里做一下初始的数据处理、异步请求等操作,当组件完成创建时就能展示这些数据。 相比Vue2没有变化。beforeMount
: 在挂载之前调用,相关的render函数首次被调用,在这里可以访问根节点,在执行mounted钩子前,dom渲染成功,相对Vue2改动不明显。onMounted
: 在挂载后调用,也就是所有相关的DOM都已入图,有了相关的DOM环境,可以在这里执行节点的DOM操作。在这之前执行beforeUpdate。beforeUpdate
: 在数据更新时同时在虚拟DOM重新渲染和打补丁之前调用。我们可以在这里访问先前的状态和dom,如果我们想要在更新之前保存状态的快照,这个钩子非常有用。相比Vue2改动不明显。onUpdated
:在数据更新完毕后,虚拟DOM重新渲染和打补丁也完成了,DOM已经更新完毕。这个钩子函数调用时,组件DOM已经被更新,可以执行操作,触发组件动画等操作beforeUnmount
:在卸载组件之前调用。在这里执行清除操作,如清除定时器、解绑全局事件等。onUnmounted
:在卸载组件之后调用,调用时,组件的DOM结构已经被拆卸,可以释放组件用过的资源等操作。
-
onActivated
– 被keep-alive
缓存的组件激活时调用。 -
onDeactivated
– 被keep-alive
缓存的组件停用时调用。 -
onErrorCaptured
– 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回false
以阻止该错误继续向上传播。
Composition API的生命周期:
除了beforecate
和created
(它们被setup
方法本身所取代),我们可以在setup
方法中访问的上面后面9个生命钩子选项:
如何看待Composition API 和 Options API?⭐⭐
Composition API和Options API是Vue.js中的两种组件编写方式。
Options API是Vue.js早期版本中使用的编写方式,通过定义一个options对象进行组件的配置,包括props、data、methods、computed、watch等选项。这种方式的优点在于结构清晰、易于理解,在小型项目中比较实用。
Composition API是Vue.js 3.x版本中新引入的一种组件编写方式,它以函数的形式组织我们的代码,允许我们将相关部分组合起来,提高了代码的可维护性和重用性。Composition API还提供了模块化、类型推断等功能,可以更好地实现面向对象编程的思想。
Composition API 更好的代码组织,更好的逻辑服用;可维护性,更好的类型推导,可拓展性更好;
两种API各有优缺点,使用哪种API取决于具体的项目需求。对于小型项目,Options API更为简单方便;对于大型项目,Composition API可以更好地组织代码。
总之,Vue.js的Composition API和Options API是为了满足不同开发者的需求而存在的,我们应该根据具体的场景选择使用哪种API,以达到更好的开发效果和代码质量。
Vue3升级了哪些重要功能?⭐⭐
-
新的API:Vue3使用createApp方法来创建应用程序实例,并有新的组件注册和调用方法。
-
emits属性::Vue 3的组件可以使用emits属性来声明事件。
-
生命周期
-
多个Fragment
-
移除.sync
-
异步组件的写法
vue2和vue3 核心 diff 算法区别?⭐
Vue 2.x使用的是双向指针遍历的算法,也就是通过逐层比对新旧虚拟DOM树节点的方式来计算出更新需要做的最小操作集合。但这种算法的缺点是,由于遍历是从左到右、从上到下进行的,当发生节点删除或移动时,会导致其它节点位置的计算出现错误,因此会造成大量无效的重新渲染。
Vue 3.x使用了经过优化的单向遍历算法,也就是只扫描新虚拟DOM树上的节点,判断是否需要更新,跳过不需要更新的节点,进一步减少了不必要的操作。此外,在虚拟DOM创建后,Vue 3会缓存虚拟DOM节点的描述信息,以便于复用,这也会带来性能上的优势。同时,Vue 3还引入了静态提升技术,在编译时将一些静态的节点及其子节点预先处理成HTML字符串,大大提升了渲染性能。
因此,总体来说,Vue 3相对于Vue 2拥有更高效、更智能的diff算法,能够更好地避免不必要的操作,并提高了渲染性能。
Vue3为什么比Vue2快?⭐⭐⭐
- 响应式系统优化:Vue3引入了新的响应式系统,这个系统的设计让Vue3的渲染函数可以在编译时生成更少的代码,这也就意味着在运行时需要更少的代码来处理虚拟DOM。这个新系统的一个重要改进就是提供了一种基于Proxy实现的响应式机制,这种机制为开发人员提供更加高效的API,也减少了一些运行时代码。
- 编译优化:Vue3的编译器对代码进行了优化,包括减少了部分注释、空白符和其他非必要字符的编译,同时也对编译后的代码进行了懒加载优化。
- 更快的虚拟DOM:Vue3对虚拟DOM进行了优化,使用了跟React类似的Fiber算法,这样可以更加高效地更新DOM节点,提高性能。
- Composition API:Vue3引入了Composition API,这种API通过提供逻辑组合和重用的方法来提升代码的可读性和重用性。这种API不仅可以让Vue3应用更好地组织和维护业务逻辑,还可以让开发人员更加轻松地实现优化。
Vue3如何实现响应式?⭐⭐⭐
使用Proxy和Reflect API实现vue3响应式。
Reflect API则可以更加方便地实现对对象的监听和更新,可以用来访问、检查和修改对象的属性和方法,比如Reflect.get、Reflect.set、Reflect.has等。
Vue3会将响应式对象转换为一个Proxy对象,并利用Proxy对象的get和set拦截器来实现对属性的监听和更新。当访问响应式对象的属性时,get拦截器会被触发,此时会收集当前的依赖关系,并返回属性的值;当修改响应式对象的属性时,set拦截器会被触发,此时会触发更新操作,并通知相关的依赖进行更新。
优点:可监听属性的变化、新增与删除,监听数组的变化
vue的数据响应式⭐⭐
Vue通过Object.defineProperty()(Vue2)或Proxy(Vue3)实现数据劫持,监视数据变化。
双向绑定通常通过v-model指令实现,监听表单元素的输入事件,自动更新数据模型,模型的变化也会自动更新到视图。
Vue3响应式原理(Proxy)⭐⭐⭐
Vue3使用Proxy
替代了Object.defineProperty
,克服了Vue2的一些局限,比如数组的监听。
const handler = {
get(target, key) {
console.log('Getting:', key);
return Reflect.get(target, key);
},
set(target, key, value) {
console.log('Setting:', key);
return Reflect.set(target, key, value);
}
};
const state = new Proxy({ message: 'Hello Vue' }, handler);
Proxy和Object.defineProperty的区别?⭐⭐
Proxy和Object.defineProperty都可以用来实现JavaScript对象的响应式,但是它们有一些区别:
-
实现方式:Proxy是ES6新增的一种特性,使用了一种代理机制来实现响应式。而Object.defineProperty是在ES5中引入的,使用了getter和setter方法来实现。
-
作用对象:Proxy可以代理整个对象,包括对象的所有属性、数组的所有元素以及类似数组对象的所有元素。而Object.defineProperty只能代理对象上定义的属性。
-
监听属性:Proxy可以监听到新增属性和删除属性的操作,而Object.defineProperty只能监听到已经定义的属性的变化。
-
性能:由于Proxy是ES6新增特性,其内部实现采用了更加高效的算法,相对于Object.defineProperty来说在性能方面有一定的优势。
综上所述,虽然Object.defineProperty在Vue.js 2.x中用来实现响应式,但是在Vue.js 3.0中已经采用了Proxy来替代,这是因为Proxy相对于Object.defineProperty拥有更优异的性能和更强大的能力。
什么是MVVM?⭐
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。
mvvm和mvc的区别?它和其他框架(JQuery)的区别是什么?哪些场景适合?⭐
mvc和mvvm其实区别不大。都是一种设计思想,主要mvc中controller演变成mvvm中的ViewModel。mvvm主要解决了mvc中大量的DOM操作使页面渲染性能降低,加载速度变慢,影响用户体验
区别:vue数据驱动,通过数据来显示视图层而不是JQuery(节点)操作
场景:数据操作比较多的场景,更加便捷
什么是虚拟dom⭐
虚拟 dom 是相对于浏览器所渲染出来的真实 dom 的,在react,vue等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然后修改样式行为或者结构,来达到更新 ui 的目的。
这种方式相当消耗计算资源,因为每次查询 dom 几乎都需要遍历整颗 dom 树,如果建立一个与 dom 树对应的虚拟 dom 对象( js 对象),以对象嵌套的方式来表示 dom 树,那么每次 dom 的更改就变成了 js 对象的属性的更改,这样一来就能查找 js 对象的属性变化要比查询 dom 树的性能开销小。
v-show和v-if指令的共同点和不同点⭐⭐
v-show 指令是通过修改元素的display的CSS属性让其显示或隐藏
v-if 指令是直接销毁和重建DOM节点,达到让元素显示和隐藏的效果
如何让CSS只在当前组件中起作用⭐
在当前文档中使用style标签,并添加scope属性
<keep-alive></keep-alive>的作用是什么?⭐
keep-alive标签包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染
聊聊Keep-alive的实现原理和缓存策略⭐
原理:
keep-alive的实现正是用到了LRU策略, 将最近访问的组件push到this.keys最后面, this,keys[0] 也就是最久没有被访问到的组件, 当缓存实例超过max设置值, 删除this.keys[0]
LRU缓存淘汰算法:
LRU算法根据数据的历史访问记录来进行记录, 其核心思想是”如果数据最近被访问过, 那么将来被访问的几率也更高”
Vue常用的修饰符?⭐
.precent:提交事件不在重载页面
.stop: 组织但即使单击事件冒泡
.self:当事件发生在该元素本身而不是子元素的时候会触发
.capture: 事件侦听, 事件发生的时候会调用
.once:事件只触发一次
什么是Vue的计算属性?⭐
在模板中放入太多的逻辑会让模板过重且难以维护, 在需要对数据进行复杂处理, 且可能多次使用的情况下, 尽量采用计算属性的方式。
好处:
- 使得数据处理结构清晰
- 依赖于数据,数据更新,处理结果自动更新
- 计算属性内容部this指向vm实例
- 在template调用时,直接写计算属性名即可
- 常用的getter方法,获取数据,也可以使用set方法改变数据
- 相较于methods, 不管依赖的数据变不变,methods都会重新计算, 但依赖数据不变的时候,computed从缓存中获取, 不会重新计算
说出至少4中vue当中的指令和它的用法?⭐
v-if:判断是否为真,然后重组、销毁DOM节点
v-for:数据循环
v-bind:class 绑定一个属性
v-model:实现双向绑定
v-on:添加事件
v-else:配合v-if使用
vue-loader是什么?使用它的用途有哪些?⭐
解析:vue文件的一个加载器
用途:js可以写es6、style样式可以scss、template可以加等
Vue中的Key到底有什么用?⭐
Key是给每一个vnode的唯一id, 依靠key, 我们diff操作可以更准确、更快速(对于简单列表页面渲染来说diff节点也更快,但会产生一些隐藏的副作用,比如可能不会产生过渡效果,或者在某些节点有绑定数据(表单)状态,会出现状态错位)
diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key与旧节点进行比对, 从而找到相应的旧节点
更准确: 因为带Key就不会出现重复现象, 在sameNode函数a.key === b.key对比中可以避免就地复用的情况。所以会更加准确,如果不加key会导致之前节点的状态被保留下来,会产生一系列的bug
更快速:key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1)
Key值的存在保证了唯一性,Vue在执行时,会对节点进行检查,如果没有key值,那么vue检查到这里有dom节点,就会对内容清空并赋新值,如果有key值存在,那么会对新老节点进行对比,比较两者key是否相同,进行调换位置或删除操作
vue中$nextclick的作用⭐
1、在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
2、数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
Vue的nextTick方法的实现原理
- Vue用异步队列的方式来控制DOM更新和nextTick回调先后执行
- mictask因为其高优先级特性, 能确保队列中的微任务在一次事件循环前辈执行完毕
- 考虑兼容问题做了microtask向macrotask的降级方案
vue中$nextTick的使用场景⭐
this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中
vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。
created()使用方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,
所以,此时this.$nextTick()就会被大量使用。
created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,所以在mounted()中操作dom基本不会存在渲染问题。
详解:
js执行是单线程的, 它是基于事件循环的。
主线程的执行过程就是一个tick,而所有的异步结果都是通过“任务队列”来调度。消息队列中存放的是一个个的任务(task)。规范中的task分为两大类, 分别是macro task和micro task,并且每个macro task结束后,都将清空所有micro task。
在浏览器环境中,常见的macro task 有 setTimeout、MessageChannel、postMessage、setImmediate
常见的micro task有 MutationObsever和Promise.then
Vue在更新DOM时是异步执行的,只要侦听到数据变化,Vue将开启一个队列, 并缓冲在同一事件循环中发生的所有数据变更。
在Vue2.5的源码中,macrotask降级的方案依次是: setImmediate、MessageChannel、setTimeout
为什么避免v-if和v-for用在一起?⭐
当vue处理指令时,v-for比v-if具有更高的优先级,通过v-if移动到容器元素,不会再重复遍历列表中的每个值,取而代之的事,我们只检查它一次,且不会再v-if为否的时候运行v-for。
v-if 和 v-for 的优先级哪个高?⭐⭐
在 vue2 中 v-for 的优先级更高。
但是在 vue3 中优先级改变了,v-if 的优先级更高。
VNode是什么?虚拟DOM是什么?⭐
Vue在页面上渲染的节点,及其子节点成为“虚拟节”,简写为“VNode”。“虚拟DOM”是由Vue组件树简历起来的整个VNode树的称呼
setup中如何获得组件实例?⭐
在 setup 函数中,你可以使用 getCurrentInstance() 方法来获取组件实例。getCurrentInstance() 方法返回一个对象,该对象包含了组件实例以及其他相关信息。
以下是一个示例:
import { getCurrentInstance } from 'vue';
export default {
setup() {
const instance = getCurrentInstance();
// ...
return {
instance
};
}
};
在上面的示例中,我们使用 getCurrentInstance() 方法获取当前组件实例。然后,我们可以将该实例存储在一个常量中,并在 setup 函数的返回值中返回。
需要注意的是,getCurrentInstance() 方法只能在 setup 函数中使用,而不能在组件的生命周期方法(如 created、mounted 等方法)中使用。另外,需要注意的是,如果在 setup 函数返回之前访问了 instance 对象,那么它可能是 undefined ,因此我们需要对其进行处理。
vue首屏加载过慢怎么优化?⭐
vue作为一个单页面应用, 如果不对路由进行处理, 在加载首页的时候, 就会将所有组件全部加载, 并向服务器请求数据, 这必将拖慢加载速度.
解决方案:
1. vue-router懒加载
就是按需加载组件, 只有当路由被访问时才会加载对应组件, 而不是在加载首页的时候就加载, 项目越大, 对首页加载的速度提升越明显
2. 使用CDN加速
在做项目时, 我们会用到很多库,在爱用CDN加载可以加快加载速度
3. gzip压缩
方法一: 使用Nginx反向代理, 配置nginx.conf文件
方法二: 使用node压缩, 需要使用compression库
4. 异步加载组件
5. 服务端渲染
使用pug/jade/ejs/vue通过应用框架Nuxt等等都可以实现后端渲染, 并且后端渲染还能对seo优化起到作用
2. Router相关 ---------
Vue-router的跳转原理:⭐⭐
vue-router实现单页面路由跳转,提供了三种方式: hash方式、history模式、abstract模式,根据mode参数来决定采用哪一种方式
● hash: 使用 URL hash 值来作路由。默认模式。
● history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
● abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端
路由之间的跳转:⭐
声明式(标签跳转):<router-view>标签用于展示路由组件,DOM节点中使用v-link进行跳转,或使用router-link标签
编程式(js跳转)
怎么定义vue-router的动态路由以及如何获取传过来的动态参数?⭐
在router目录下的index.js文件中,对path属性加上/:id
使用router对象的params id
vue-router有哪几种导航钩子?以及它的参数?⭐
第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
第二种:组件内的钩子
第三种:单独路由独享组件
beforeRouteEnter、afterEnter、beforeRouterUpdate、beforeRouteLeave
参数:有to(去的那个路由)、from(离开的路由)、next(一定要用这个函数才能去到下一个路由,如果不用就拦截)最常用就这几种
Vue的路由实现: hash模式和history模式(Vue的两种状态)⭐
1. hash——即地址栏URL的#符号,特点: 通过window.onhashchange的监听, 匹配不同的url路径,进行解析,加载不同的组件,然后动态的渲染出区域内的html内容,不会被包含在HTTP请求中,对后端完全没有影响
HashHistory有两个方法:
HashHistory.push()是将路由添加到浏览器访问历史的栈顶
hashHistory.replace( ) 是替换掉当前栈顶的路由
因为hash发生变化的url都会被浏览器历史访问栈记录下来,这样一来,尽管浏览器没有请求服务器,但是页面状态和url一一关联起来的,浏览器还是可以进行前进后退的
2. history —— 利用了HTML5 History Interface中新增的pushState()和replaceState()方法。这两个方式应用于浏览器的历史记录栈,提供了对历史记录的修改功能。history模式不怕页面的前进和后腿,就怕刷新,当刷新时,如果服务器没有相应的响应或者资源,就会刷出404,而hash模式不会
$router和$route的区别⭐⭐
- $route从当前router跳转对象里面可以获取name、path、query、params等(<router-link>传的参数有this.$route.query或者this.$route.params接收)
- $router为VueRouter实例。想要导航到不同URL,则使用$router.push方式,返回上一个history也是使用$router.go方法
3. vuex相关
Vuex的五大属性⭐⭐⭐
Vuex有五个核心概念:state、getters、mutations、actions、modules
state => 基本数据
getters => 从基本数据派生的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步
modules => 模块化Vuex
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
doubleCount: state => state.count * 2
}
});
不用Vuex会带来什么问题?⭐
- 可维性会下降,想修改数据要维护三个地方
- 可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的;
- 增加耦合,大量的上传派发,会让耦合性大大增加。而Vue用Component就是为了减少耦合
谈谈pinia?⭐⭐
Pinia 是 Vue 官方团队成员专门开发的一个全新状态管理库,并且 Vue 的官方状态管理库已经更改为了 Pinia。在 Vuex 官方仓库中也介绍说可以把 Pinia 当成是不同名称的 Vuex 5,这也意味不会再出 5 版本了。
优点:
1. 更加轻量级,压缩后提交只有1.6kb。
2. 完整的 TS 的支持,Pinia 源码完全由 TS 编码完成。
3. 移除 mutations,只剩下 state 、 actions 、 getters 。
4. 没有了像 Vuex 那样的模块镶嵌结构,它只有 store 概念,并支持多个 store,且都是互相独立隔离的。当然,你也可以手动从一个模块中导入另一个模块,来实现模块的镶嵌结构。
5. 无需手动添加每个 store,它的模块默认情况下创建就自动注册。
6. 支持服务端渲染(SSR)。
7. 支持 Vue DevTools。
8. 更友好的代码分割机制,传送门。
结语
🔥如果文章对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下小老弟,蟹蟹大咖们~