引言💭
总结一下最近面试碰到的vue考点。
一、Vue 3 的常用 API
ref
和 reactive
ref
:用于创建基本数据类型(如字符串、数字、布尔值等)的响应式引用。ref
通过.value
来访问和修改数据。reactive
:用于创建对象或数组的响应式数据,直接对对象进行响应式代理。修改对象的属性时,可以直接通过属性名来访问和修改。
computed
- 用于创建计算属性,计算属性会基于它所依赖的响应式数据进行缓存。只有依赖的响应式数据发生变化时,才会重新计算。适用于衍生数据或需要基于其他数据计算的场景。
watch
- 用于监听某个响应式数据的变化,并执行副作用操作。适合用于异步操作或其他副作用(如数据存储、API 请求等)。
生命周期函数(组合式 API)
onMounted
、onUpdated
、onUnmounted
:这些生命周期函数在组件的不同生命周期阶段执行,类似于 Vue 2 的生命周期钩子。- 它们与 Vue 2 的选项式 API 生命周期钩子不同,采用了组合式 API,更加灵活和清晰。
defineComponent
- 用于定义组件,是 Vue 3 的标准组件定义方式。它支持组合式 API 和 TypeScript 类型推导,增强了组件的可读性和类型安全。
provide
和 inject
provide
和inject
是 Vue 3 中用于跨层级组件通信的 API。父组件通过provide
提供数据,子组件通过inject
获取数据,适用于多层级嵌套的组件树中。
nextTick
- 用于在 DOM 更新后执行某些操作。通常在修改数据后,Vue 会异步更新 DOM,而
nextTick
可以保证 DOM 更新完成后执行回调函数。
useContext
- 用于获取当前组件的上下文,适用于函数式组件中访问 Vue 的上下文信息。
二、ref
和 reactive
的区别
ref
用于创建基本数据类型的响应式引用,它会包装原始数据,如字符串、数字等,访问时需要通过.value
。reactive
用于创建对象或数组的响应式数据,直接对对象进行响应式代理,可以直接通过属性名来访问。
这两者可以结合使用,例如:
ini
const count = ref(0);
const user = reactive({ name: 'Alice', age: 25 });
三、computed
和 watch
的区别
-
computed
:适用于需要衍生数据或缓存计算结果的场景。它只会在依赖的数据变化时重新计算,避免不必要的性能开销。- 适用场景:表单的校验规则、动态标题、数据转换等。
-
watch
:用于侦听响应式数据的变化,并执行副作用操作。适用于异步操作或复杂的副作用,如数据提交、API 请求等。- 适用场景:请求外部 API、表单提交、页面跳转等。
四、Vue 2 的 mixin
和 Vue 3 的 hooks
的相似之处和区别
相似之处
mixin
和hooks
都可以用于逻辑复用,将多个组件中共享的功能提取到外部,使得代码更加模块化和可维护。
区别
- Mixin:Vue 2 的 mixin 是将多个组件选项中的逻辑混入当前组件,可能导致命名冲突或代码可维护性差,尤其在大型应用中。
- Hooks(Vue 3) :Vue 3 提供的组合式 API 允许更加灵活和模块化的代码组织,避免了 mixin 中的命名冲突,逻辑更加清晰和可组合。
五、v-if
和 v-for
的使用及 key
的作用
v-if
:用于根据条件渲染 DOM 元素。适用于动态显示/隐藏元素。v-for
:用于渲染列表,通常与数组或对象结合使用进行渲染。key
:在v-for
中使用key
来标识每个节点。key
有助于 Vue 更高效地更新 DOM,确保虚拟 DOM 的正确复用,从而提高性能。
六、Vue 3 组件生命周期及替代 API
在 Vue 3 中,组件生命周期方法与 Vue 2 略有不同。Vue 2 中的生命周期方法包括:beforeCreate
、created
、beforeMount
、mounted
、beforeUpdate
、updated
、beforeDestroy
、destroyed
。这些方法描述了组件从创建到销毁的各个阶段。
- beforeCreate: 在实例创建之前被调用。
- created: 实例创建后调用,数据观测和事件配置已完成,但 DOM 尚未挂载。
- beforeMount: 在挂载开始之前调用,此时 DOM 尚未被渲染。
- mounted: 组件挂载完成后调用,DOM 已渲染并可访问。
- beforeUpdate: 在组件数据变化时调用,DOM 尚未更新。
- updated: 在组件数据变化后,DOM 更新完毕后调用。
- beforeDestroy: 在组件销毁前调用。
- destroyed: 在组件销毁后调用。
在 Vue 3 中,组合式 API 替代了传统的生命周期方法。常用的替代方法包括:
onMounted
: 替代mounted
,用于在组件挂载完成后执行操作。onUpdated
: 替代updated
,用于在组件更新后执行操作。
通过组合式 API,生命周期方法可以在多个 setup()
中进行逻辑复用,增强了代码的可维护性和复用性。
七、Vue 2 与 Vue 3 的区别
- 性能:Vue 3 引入了更高效的虚拟 DOM 和响应式系统,整体性能得到了大幅提升。特别是在大型应用中,Vue 3 的响应式性能比 Vue 2 更优。
- 组合式 API :Vue 3 增加了组合式 API(Composition API),让开发者能通过
setup()
函数集中定义响应式状态、计算属性和生命周期钩子,提升了逻辑复用性和代码的可读性。 - TypeScript 支持:Vue 3 对 TypeScript 的支持更加完善,提供了更好的类型推导和静态类型检查,增强了开发体验。
- 响应式系统 :Vue 3 使用了基于
Proxy
的响应式系统,相比于 Vue 2 中使用的Object.defineProperty
,Proxy
提供了更高的性能和更强的灵活性,能够更好地处理嵌套对象和数组。
八、Vue 2 响应式与 Vue 3 响应式的区别
- Vue 2 : 使用
Object.defineProperty
通过劫持对象的 getter 和 setter 来实现响应式。这种方式的缺点包括无法检测到数组索引的变化,且对于嵌套对象的处理也相对有限。 - Vue 3 : 使用
Proxy
实现响应式,提供了更强大的功能。Proxy
可以直接代理整个对象,支持嵌套对象、数组及其变化的检测,并且性能也比Object.defineProperty
更好。
九、Vue 组件通信
Vue 提供了多种方式来实现组件间的通信,主要包括以下几种:
-
父子组件通信:
- 父组件通过
props
向子组件传递数据。 - 子组件通过
$emit
向父组件发送事件,实现双向数据流。
- 父组件通过
-
兄弟组件通信:
- 通过公共父组件传递数据,父组件将数据传递给两个兄弟组件。
- 或者通过
provide
和inject
实现祖先和后代组件之间的通信。
-
跨层级通信:
- 可以使用状态管理库,如
Vuex
或Pinia
,来管理全局状态,确保跨层级的组件都能访问和修改共享的数据。 - 事件总线也是一种常见的跨层级通信方式,虽然在 Vue 3 中已经不推荐使用。
- 可以使用状态管理库,如
十、Vuex 与 Pinia 的区别
- Vuex :Vuex 是 Vue 2.x 的官方状态管理库。它使用
mutations
和actions
来处理状态变更,管理全局状态,并且需要通过显式的commit
和dispatch
操作。 - Pinia:Pinia 是 Vue 3 推荐的状态管理库。它基于组合式 API,支持更好的类型推导、响应式状态管理,并且 API 更加简洁。Pinia 在 Vue 3 中的表现更自然,并且对于 TypeScript 的支持也更加友好。
总结:
- Vuex 适用于 Vue 2 项目,而 Pinia 更适合 Vue 3 项目。
- Pinia 提供了更简洁和现代化的 API,更好地集成了 Vue 3 的组合式 API。
十一、选项式 API 和 组合式 API 的区别
-
选项式 API:
- 通过组件的选项(如
data
,methods
,computed
,watch
等)来组织逻辑。 - 结构化明确,但对于大型或复杂的应用来说,代码容易变得繁琐且不易维护。
- 适用于小型到中型的项目,易于上手。
- 通过组件的选项(如
-
组合式 API:
- 通过函数来组织组件的逻辑,使用
setup()
函数进行组合。 - 逻辑复用性更强,可以按功能拆分逻辑,提高可维护性和可扩展性。
- 特别适用于复杂的组件,能够提高代码的模块化程度,增强可读性和测试性。
- 通过函数来组织组件的逻辑,使用
总结:选项式 API 适合小型或中型项目,而组合式 API 更适合复杂或大型项目,且具有更高的灵活性和可复用性。
十二、v-show 和 v-if 的区别
-
v-show
:- 仅通过修改元素的
display
样式来控制元素的显示和隐藏。 - 当切换频繁时,使用
v-show
比v-if
性能更优,因为它不涉及元素的销毁和重新创建。 - 适用于需要频繁切换的场景。
- 仅通过修改元素的
-
v-if
:- 根据条件判断是否渲染该元素,条件不成立时,元素将从 DOM 中完全移除。
- 初次渲染时性能较差,尤其是在条件发生变化时,Vue 会销毁并重新创建 DOM 元素。
- 适用于不常切换的元素。
总结 :v-show
适合频繁切换的场景,v-if
适合不常切换的元素,能有效优化性能。
十三、Vue 中的虚拟 DOM,diff 算法
-
虚拟 DOM:
- Vue 使用虚拟 DOM 来优化页面渲染过程。当组件的数据发生变化时,Vue 会首先创建一个虚拟 DOM 树,而不是直接修改真实的 DOM。
-
Diff 算法:
- 当数据发生变化时,Vue 会用新生成的虚拟 DOM 树与旧的虚拟 DOM 树进行比较(diff)。它通过最小化的更新策略,计算出最小的 DOM 变更,最终应用到真实的 DOM 上。
- 这一过程显著提升了渲染性能,尤其是在数据频繁变动的场景中。
总结:虚拟 DOM 和 Diff 算法的结合使得 Vue 在进行 DOM 更新时更加高效,减少了不必要的 DOM 操作,提高了性能。
十四、v-bind 和 v-model
-
v-bind
:- 用于动态绑定 HTML 属性或组件的特性,允许我们将一个变量或表达式的值绑定到属性上。例如:
v-bind:href="url"
。 - 适用于需要动态改变属性值的场景。
- 用于动态绑定 HTML 属性或组件的特性,允许我们将一个变量或表达式的值绑定到属性上。例如:
-
v-model
:- 实现表单元素的双向数据绑定,常用于
input
、textarea
等表单元素。它会自动绑定元素的value
和相应的事件(如input
事件)来同步更新数据。 - 在 Vue 3 中,
v-model
也可以用于自定义事件的双向绑定。
- 实现表单元素的双向数据绑定,常用于
总结 :v-bind
用于单向绑定属性,而 v-model
用于双向数据绑定,特别适合表单元素的交互。
十五、Vue 3 里面的劫持有哪些
-
Vue 3 使用 Proxy 来实现响应式系统,取代了 Vue 2 中的
Object.defineProperty
。- Proxy 可以拦截对象的读取、设置、删除等操作,并通过代理机制来触发视图的更新。
- 通过对对象进行代理,Vue 3 可以更高效地追踪数据变化,并实现响应式更新。
总结 :Vue 3 通过 Proxy
实现对数据的劫持和响应式更新,较 Vue 2 提升了性能并简化了代码逻辑。
十六、Vue 的插槽
Vue 插槽是一个强大的功能,允许父组件将内容传递给子组件,增加了组件的灵活性和可复用性。插槽有三种主要类型:
-
默认插槽:子组件定义一个插槽,父组件可以在该插槽中传递内容。子组件会渲染父组件传递的内容。
xml<!-- 父组件 --> <child-component> <p>这是父组件传递的内容</p> </child-component> <!-- 子组件 --> <template> <slot></slot> <!-- 显示父组件的内容 --> </template>
-
具名插槽:子组件定义多个具名插槽,父组件可以根据名称来传递不同的内容,增强了插槽的灵活性。
xml<!-- 父组件 --> <child-component> <template v-slot:header> <h1>这是头部</h1> </template> <template v-slot:footer> <footer>这是底部</footer> </template> </child-component> <!-- 子组件 --> <template> <slot name="header"></slot> <slot name="footer"></slot> </template>
-
作用域插槽:作用域插槽允许父组件传递数据到插槽中,这样父组件能够通过插槽访问子组件的数据或状态。
xml<!-- 父组件 --> <child-component> <template v-slot:default="slotProps"> <p>插槽数据: {{ slotProps.message }}</p> </template> </child-component> <!-- 子组件 --> <template> <slot :message="message"></slot> <!-- 传递数据给插槽 --> </template> <script> export default { data() { return { message: '这是子组件传递的消息' }; } } </script>
十七、Vue 追踪机制
Vue 的响应式系统利用 依赖收集 和 更新机制 ,确保当数据变化时,相关的视图或组件会自动重新渲染。Vue 通过 Proxy
实现数据的响应式,当数据属性发生变化时,Vue 会自动触发相应的视图更新。
Vue 追踪机制的核心是:
- 依赖收集:当组件渲染时,它会读取使用的数据属性并将其注册到依赖队列中,确保当这些数据发生变化时,能够触发更新。
- 懒更新:只有数据发生变化时,相关的 DOM 会重新渲染,减少不必要的性能开销。
十八、Vue SSR 的实现原理
Vue SSR(服务器端渲染)通过在服务器端渲染页面,再将渲染后的 HTML 发送给客户端,可以显著提升 SEO 和首屏加载性能。在 Vue 3 中,SSR 通过 renderToString
和 createApp
实现。
createApp
:用于创建 Vue 应用的实例。renderToString
:将 Vue 应用渲染为 HTML 字符串并返回给客户端。
这种机制让客户端能够尽早展示页面内容,而不是等待 JavaScript 加载和执行后再渲染,从而提升了性能和 SEO。
十九、Pinia 中的数据在哪里储存
Pinia 是 Vue 3 的状态管理库,默认情况下,Pinia 的状态存储在内存中。这意味着,当页面刷新时,所有的状态数据会丢失。不过,Pinia 提供了插件机制,可以将状态持久化到浏览器的存储中,如 localStorage
或 sessionStorage
。
使用 Pinia 插件时,可以选择将状态存储到本地存储中,确保即使页面刷新,状态也能保持。
javascript
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
二十、Vue Router 有几种模式,有什么区别
Vue Router 提供了三种模式来管理路由和 URL 地址:
-
hash
模式 :通过 URL 中的哈希值(#
)来进行路由控制,兼容性最好,但会在 URL 中留下#
字符。适用于所有浏览器。示例:
bashhttps://example.com/#/home
-
history
模式 :利用 HTML5 History API 实现路由跳转,URL 中没有哈希值,URL 更简洁、易读。需要服务器配置支持,以避免直接刷新页面时出现 404 错误。Vite 开发服务器默认支持 history 模式,所有路径请求都会自动回退到 index.html,不会出现 404。
示例:
arduinohttps://example.com/home
二十一、状态管理库什么时候用到
状态管理库(如 Vuex 或 Pinia)通常在以下场景中使用:
- 应用中有多个组件需要共享同一份状态,避免组件间的直接传递或通过事件传递的复杂性。
- 状态的变化较为复杂或频繁,单一组件无法处理状态变化时,采用状态管理库能使状态变得更为可控和可预测。
- 需要跨多个视图或页面共享状态(如用户登录状态、购物车数据等)。
Vuex 和 Pinia 提供了一种集中式的方式来管理状态,使得在多个组件间共享状态更加清晰和高效。
二十二、动态路由怎么实现
动态路由允许在路由配置中使用参数来构建灵活的 URL,可以通过以下方式实现:
- 动态路由参数 :通过在路由路径中使用
:param
语法来定义动态路由,例如/user/:id
,id
就是动态参数,可以在路由视图中访问到。 - 懒加载 :可以通过动态导入来实现组件的懒加载,例如
component: () => import('./views/User.vue')
,这样只有在路由被访问时,组件才会被加载,减少了初始加载的体积。 - beforeEnter 钩子 :通过
beforeEnter
钩子可以在路由进入前做数据加载,确保数据准备好再渲染页面。
二十三、Vue 3 发布订阅者模式
Vue 3 的响应式系统基于发布/订阅模式。每当数据发生变化时,所有订阅该数据的组件或函数都会收到通知并更新。这是通过 Proxy
实现的,当数据变化时,Proxy 会触发依赖收集,并在数据变化时通知相关的视图更新,从而实现响应式。
二十四、keep-alive 是什么?如何使用
keep-alive
是 Vue 提供的一个内置组件,它用于缓存不活动的组件,避免它们重新渲染,从而提升性能。常用于多页面的场景,避免频繁的组件销毁和重建。
-
使用方式 :将组件包裹在
keep-alive
标签内:xml<keep-alive> <my-component /> </keep-alive>
-
控制缓存 :通过
include
和exclude
属性,可以控制哪些组件需要被缓存,例如:xml<keep-alive include="ComponentA, ComponentB"> <my-component /> </keep-alive>
这将仅缓存
ComponentA
和ComponentB
。
二十五、Vue 如何实现懒加载
Vue 中的懒加载通常通过动态导入实现。例如,在 Vue Router 中可以通过 import()
动态导入组件,从而实现路由级别的懒加载:
javascript
const routes = [
{
path: '/about',
component: () => import('./views/About.vue')
}
]
这种方式只有在访问到该路由时才会加载相应的组件,能够减少初始加载的包体积,提升性能。
二十六、Vue 打包需要做什么配置
Vue 的打包通常使用 webpack
或 Vite
进行配置,常见的配置项包括:
- 代码分割 :使用
import()
动态导入组件,实现按需加载,减少初始加载体积。 - 资源优化:配置图片压缩、字体优化等,减少资源文件大小。
- 环境变量 :配置不同的环境变量(如
process.env.NODE_ENV
)来区分开发和生产环境,进行不同的优化和配置。 - 压缩和混淆:在生产环境下进行代码压缩和混淆,减小最终打包的文件大小。
二十七、Vue 的优点
- 易于上手:Vue 提供了清晰、易懂的文档,学习曲线平缓,适合快速入门。
- 响应式系统性能优秀 :Vue 的响应式系统基于
Proxy
,性能高效,能够处理复杂的状态变化。 - 组件化结构:Vue 提供了组件化开发方式,方便开发和维护大型应用。
- 灵活性高:支持选项式和组合式 API,开发者可以根据需求选择适合的方式来组织代码。
二十八、Vue 中的 nextTick
nextTick
是 Vue 提供的一个 API,用于在 DOM 更新之后执行回调。由于 Vue 的响应式更新是异步的,nextTick
可以确保在数据变化之后,获取到更新后的 DOM 状态。例如,在更新数据之后想要访问 DOM 元素,可以使用 nextTick
:
javascript
this.$nextTick(() => {
// DOM 更新完成后执行
});
它常用于在 Vue 更新 DOM 后进行某些操作,比如获取新的 DOM 状态或执行动画等。
结语✒️
这就是最近看见的vue相关的面试题了,比较片面,深入了解还需自行查阅,持续更新中......
