Vue 框架相关面试题及答案
-
什么是 Vue?它有哪些核心特性?
Vue 是一套用于构建用户界面的渐进式 JavaScript 框架,核心特性包括:
① 响应式数据绑定(数据驱动视图);
② 组件化开发(复用 UI 和逻辑);
③ 虚拟 DOM(提升渲染性能);
④ 指令系统(如
v-if
、v-for
简化 DOM 操作);⑤ 生命周期钩子(控制组件生命周期);
⑥ 过渡动画系统(实现元素切换效果);
⑦ 单文件组件(
.vue
文件,整合 HTML、CSS、JS)。 -
Vue 的双向数据绑定原理是什么?Vue2 和 Vue3 的实现有何区别?
双向数据绑定指数据变化自动更新视图,视图变化同步更新数据,核心是数据劫持 +发布 - 订阅模式。
-
Vue2:通过
Object.defineProperty()
劫持对象属性的getter
和setter
:getter
收集依赖(Watcher),setter
触发依赖更新视图;视图更新通过v-model
(语法糖,结合v-bind
和input
事件)同步数据。 -
Vue3:改用
Proxy
代理整个对象,支持监听数组变化、新增属性、嵌套对象等,解决 Vue2 的局限性(如无法监听数组索引修改);依赖收集更高效,基于effect
实现响应式。
-
Vue 的生命周期钩子有哪些?分别在什么阶段执行?
生命周期指组件从创建到销毁的过程,核心钩子:
-
初始化阶段:
beforeCreate
(实例初始化后,数据和方法未就绪)→created
(数据和方法就绪,DOM 未生成)。 -
挂载阶段:
beforeMount
(模板编译完成,未挂载到 DOM)→mounted
(DOM 挂载完成,可操作 DOM)。 -
更新阶段:
beforeUpdate
(数据更新,DOM 未重新渲染)→updated
(DOM 重新渲染完成)。 -
销毁阶段:
beforeUnmount
(组件销毁前,可清理资源)→unmounted
(组件销毁,事件监听器解绑)。(Vue3 中
beforeDestroy
改为beforeUnmount
,destroyed
改为unmounted
)
- Vue 组件通信的方式有哪些?请分别说明适用场景。
-
父子组件:
-
①
props
/$emit
(父传子用props
,子传父用$emit
触发自定义事件,最常用); -
②
$parent
/$children
(直接访问父 / 子实例,不推荐,耦合度高); -
③
ref
(父组件通过ref
获取子组件实例)。 -
跨级 / 兄弟组件:
-
①
provide
/inject
(祖先组件提供数据,后代组件注入,适合深层传递); -
② 事件总线(
EventBus
,通过$on
/$emit
,适合中小型项目); -
③ Vuex/Pinia(状态管理库,适合大型项目共享状态)。
-
其他:
-
① 路由参数(
$route.params
传递页面间数据); -
② 本地存储(
localStorage
共享非响应式数据)。
v-if
和v-show
的区别是什么?分别适用于什么场景?
-
实现方式:
v-if
通过添加 / 移除 DOM 元素 控制显示(隐藏时不渲染);v-show
通过 ** 设置display: none
** 控制显示(元素始终存在于 DOM)。 -
性能:初始渲染时
v-if
开销小(不渲染),v-show
开销大(需渲染);频繁切换时v-if
开销大(DOM 操作),v-show
开销小(样式切换)。 -
场景:
v-if
适合条件很少改变的场景(如权限判断);v-show
适合频繁切换的场景(如标签页切换)。
- 什么是计算属性(
computed
)和监听器(watch
)?它们的区别和使用场景是什么?
-
计算属性:基于依赖数据动态计算的属性,具有缓存机制(依赖不变则返回缓存值),必须返回结果。
场景:复杂逻辑计算(如购物车总价 = 单价 × 数量)、数据格式化(如日期转换)。
-
监听器:监听数据变化并执行回调,支持异步操作,无返回值。
场景:数据变化时的副作用(如搜索框输入后请求接口、表单验证)。
区别:计算属性侧重 "结果",监听器侧重 "过程";计算属性缓存结果,监听器每次变化都触发。
-
Vue 的
v-for
指令如何使用?为什么要加key
?key
的作用是什么?v-for
用于循环渲染列表,语法:v-for="(item, index) in list" :key="item.id"
。key
的作用:① 帮助 Vue 识别列表中每个元素的唯一性,提升 diff 算法效率(避免不必要的 DOM 复用);
② 确保组件 / 元素状态正确(如输入框内容不错乱)。
注意:
key
需为唯一值(如 ID),不建议用index
(可能导致元素复用异常,尤其列表有增删时)。 -
Vue 的组件生命周期中,
created
和mounted
有什么区别?
-
created
:实例创建完成后调用,此时数据和方法已初始化,但 DOM 未生成($el
不存在),无法操作 DOM。用途:发起初始化数据请求(如获取列表数据)、设置定时器等。
-
mounted
:模板挂载到 DOM 后调用,$el
存在,可操作 DOM(如获取元素尺寸、初始化第三方插件)。用途:DOM 相关操作(如初始化图表、绑定事件监听器)。
-
什么是 Vue 的插槽(Slot)?有哪些类型?如何使用?
插槽用于父组件向子组件传递内容,使组件更灵活复用,类型:
-
匿名插槽(默认插槽):子组件用
<slot>
接收,父组件直接在子组件标签内写内容。示例:
html
<!-- 子组件 -->
\<template>\<div>\<slot>默认内容\</slot>\</div>\</template>
<!-- 父组件 -->
<Child>自定义内容\</Child>
-
具名插槽:子组件用
<slot name="xxx">
定义,父组件用<template #xxx>
传递对应内容。 -
作用域插槽:子组件通过
<slot :data="item">
传递数据,父组件用<template #default="scope">
接收(如自定义列表项渲染)。
-
Vuex 的核心概念有哪些?它们的作用是什么?
Vuex 是 Vue 的状态管理库,用于集中管理组件共享状态,核心概念:
-
state
:存储共享状态(唯一数据源,如state.count
)。 -
getters
:基于state
的计算属性(如getters.doubleCount = state => state.count * 2
)。 -
mutations
:修改state
的唯一方式(同步操作),通过store.commit('increment')
触发。 -
actions
:处理异步操作(如请求接口),通过store.dispatch('fetchData')
触发,最终调用mutations
。 -
modules
:将大状态拆分为模块(每个模块有独立的state
、mutations
等,解决状态臃肿)。
-
Vue Router 的路由模式有哪些?它们的区别是什么?
Vue Router 支持两种路由模式:
-
hash
模式(默认):URL 中包含#
(如http://xxx/#/home
),通过hashchange
事件监听路由变化,兼容性好(支持 IE8+),无需服务端配置。 -
history
模式:URL 无#
(如http://xxx/home
),基于 HTML5 的history.pushState()
API,需服务端配置(避免刷新 404),URL 更美观。切换方式:在
new VueRouter({ mode: 'history' })
中配置。
-
什么是 Vue 的混入(mixin)?它的优缺点是什么?
混入是复用组件逻辑的方式,将组件选项(
data
、methods
等)提取到混入对象,组件通过mixins: [mixin]
引入。优点:代码复用,减少重复逻辑(如多个组件需要相同的表单验证方法)。
缺点:
① 命名冲突(组件选项覆盖混入选项,复杂场景难维护);
② 逻辑分散(多个混入可能导致组件逻辑来源不清晰);
③ Vue3 推荐用组合式 API 替代。
-
Vue3 的组合式 API(Composition API)与 Vue2 的选项式 API(Options API)有什么区别?
-
组织方式:选项式 API 按
data
、methods
、computed
等选项分类;组合式 API 通过setup
函数按逻辑功能组织(如将表单相关逻辑放在一起)。 -
复用性:选项式 API 依赖
mixin
,易冲突;组合式 API 通过自定义 Hook(如useForm()
)复用逻辑,更清晰。 -
类型支持:组合式 API 对 TypeScript 更友好,类型推断更准确。
-
灵活性:组合式 API 可在
setup
中随时引入逻辑,选项式 API 受选项结构限制。
- Vue3 中的
ref
和reactive
有什么区别?如何选择使用?
-
ref
:用于包装基本类型数据(number
、string
等),返回带value
属性的响应式对象(访问时需.value
,模板中可省略)。示例:
const count = ref(0); count.value++
。 -
reactive
:用于包装对象 / 数组,返回响应式代理对象(直接访问属性,无需.value
)。示例:
const user = reactive({ name: 'vue' }); user.name = 'vue3'
。选择:基本类型用
ref
,对象 / 数组用reactive
;ref
也可包装对象(内部自动转为reactive
)。
-
Vue 的自定义指令有什么作用?如何注册和使用?
自定义指令用于封装 DOM 操作(如聚焦输入框、权限控制),分为全局和局部指令。
使用:
<input v-focus>
。钩子函数:
bind
(绑定指令时)、inserted
(元素插入 DOM 时)、update
(组件更新时)等。
- 全局注册:
js
Vue.directive('focus', {
inserted(el) { el.focus(); } // 元素插入DOM时执行
});
- 局部注册(组件内):
js
directives: {
focus: { inserted(el) { el.focus(); } }
}
-
什么是 Vue 的过滤器(filter)?如何使用?Vue3 为什么移除过滤器?
过滤器用于格式化数据(如日期、货币),在模板中用
|
调用。示例:
html
<!-- 局部过滤器 -->
<template>{{ date | formatDate }}\</template>
<script>
export default {
filters: { formatDate(date) { /\* 格式化逻辑 \*/ } }
}
</script>
Vue3 移除原因:
① 功能可被计算属性或方法替代;
② 过滤器不支持参数类型推断,对 TypeScript 不友好;
③ 增加学习成本,不符合 "单一职责" 原则。
-
Vue 组件中
props
的校验规则有哪些?如何设置?props
可设置校验规则,确保父组件传递的数据符合预期,规则包括:
json
props: {
age: {
type: Number,
required: true,
validator: (v) => v >= 0
},
user: {
type: Object,
default: () => ({ name: 'guest' })
}
}
-
类型校验:
type: String/Number/Array/Object/Function
等。 -
必填校验:
required: true
。 -
默认值:
default: '默认值'
(对象 / 数组默认值需用函数返回)。 -
自定义校验:
validator: (value) => { return value > 0; }
。示例:
-
Vue 的过渡动画系统如何使用?有哪些常用的过渡类名?
Vue 提供
<transition>
组件实现元素进入 / 离开的过渡效果,常用类名(v-
为默认前缀,可自定义):
html
<transition name="fade">
<div v-if="show">动画元素\</div>
</transition>
<style>
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>
-
进入前:
v-enter-from
;进入中:v-enter-active
;进入后:v-enter-to
。 -
离开前:
v-leave-from
;离开中:v-leave-active
;离开后:v-leave-to
。示例:
-
Pinia 与 Vuex 相比有哪些改进?为什么推荐使用 Pinia?
Pinia 是 Vue3 推荐的状态管理库,相比 Vuex 的改进:
html
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: { increment() { this.count++; } }
});
-
简化 API:无
mutations
,直接在actions
中修改状态(支持同步和异步)。 -
更好的 TypeScript 支持:类型推断更自然,无需额外类型声明。
-
模块化设计:每个
store
都是独立模块,无需modules
嵌套。 -
支持 Vue2 和 Vue3:兼容性更好。
-
轻量:体积更小,性能更优。
示例(Pinia):
- 如何优化 Vue 项目的性能?
-
代码层面:
-
① 合理使用
v-if
和v-show
; -
②
v-for
避免与v-if
同用(先用computed
过滤数据); -
③ 组件拆分(避免过大组件);
-
④ 使用
memo
/shallowRef
缓存组件或数据。 -
渲染优化:
-
① 列表加
key
; -
② 大列表用虚拟滚动(如
vue-virtual-scroller
); -
③ 避免不必要的响应式数据(用
markRaw
标记非响应式对象)。 -
打包优化:
-
① 路由懒加载(
const Home = () => import('./Home.vue')
); -
② 按需引入第三方库(如 Element Plus);
-
③ 压缩代码(Tree-Shaking、Gzip)。
-
其他:
-
① 合理使用缓存(
keep-alive
缓存组件); -
② 减少 watch 深度监听;
-
③ 避免频繁操作 DOM(用 Vue 的响应式替代)。