1. Vue 的核心特点是什么?
解答:
- 渐进式框架:你可以按需使用 Vue 的功能(比如只用核心的视图层,或配合路由、状态管理),不用一次性引入所有功能,适合从小项目到大型应用的逐步扩展。
- 双向数据绑定 :在表单场景下,
v-model实现数据(data)和视图(DOM)的双向同步(底层是v-bind+v-on语法糖)。 - 组件化:将 UI 拆分成独立、可复用的组件(比如 Button、Card),降低复杂度,便于维护。
- 虚拟 DOM:和 React 类似,用 JS 对象模拟真实 DOM,更新时对比新旧 VDOM 差异,只更新变化的部分,减少 DOM 操作。
- 指令系统 :提供
v-if、v-for、v-bind等指令,简化 DOM 操作(无需手动写 JS 操作 DOM)。
Vue 整体就是数据驱动视图,不用直接操作 DOM,只需要关注数据逻辑,开发效率高、易上手、生态也成熟。
2. Vue2 和 Vue3 的核心区别?
| 维度 | Vue2 | Vue3 |
|---|---|---|
| 核心架构 | Options API(选项式):按 data/methods/mounted 组织代码 |
Composition API(组合式):按逻辑功能组织代码(比如把请求相关的代码放在一起) |
| 响应式原理 | Object.defineProperty(只能监听对象属性,无法监听数组 / 新增属性) | Proxy(代理整个对象,支持数组 / 新增属性,性能更好) |
| 生命周期 | beforeCreate/created/beforeMount/mounted 等(选项式) |
新增 setup(替代 beforeCreate/created),生命周期钩子以 onXXX 形式调用(比如 onMounted) |
| 根节点 | 只能有一个根节点(比如必须用 <div> 包裹) |
支持多个根节点(无需包裹) |
| 性能 | 重渲染时全量更新组件 | 编译优化(静态提升、PatchFlag),只更新动态节点,性能提升~50% |
| 类型支持 | 对 TypeScript 支持差 | 原生支持 TypeScript |
|------|------------------|-----------------|
| 类型支持 | 对 TypeScript 支持差 | 原生支持 TypeScript |
3. 什么是 MVVM 模型?Vue 如何体现 MVVM?
解答:
-
MVVM 是 Model-View-ViewModel 的缩写:
- Model:数据层(比如 Vue 中的
data、接口返回的数据); - View:视图层(DOM 结构,比如模板、页面);
- ViewModel:连接 Model 和 View 的中间层(Vue 的核心实例),负责数据绑定和事件监听。
- Model:数据层(比如 Vue 中的
-
Vue 对 MVVM 的体现:
- ViewModel 就是 Vue 实例(
new Vue({})或setup中的响应式数据); - Model 变化时,ViewModel 自动更新 View(数据驱动视图);
- View 触发事件时,ViewModel 通知 Model 变化(比如
v-on绑定事件修改data); - 开发者无需手动操作 DOM,只需关注数据和逻辑。
- ViewModel 就是 Vue 实例(
-
总结:
-
MVVM 是 Model-View-ViewModel 的缩写。
• Model:数据层,存放业务数据。
• View:视图层,就是页面展示的 HTML。
• ViewModel:Vue 实例,负责连接 Model 和 View。
在 Vue 里体现为:
• 数据驱动视图:Model 数据变化,ViewModel 自动更新 View。
• 视图驱动数据:View 触发操作,ViewModel 自动修改 Model。
通过这种双向绑定,我们不用手动操作 DOM,只需要关注数据逻辑。
4.vue中的双向绑定原理是什么?
Vue2 的双向绑定,底层是通过 Object.defineProperty 实现数据劫持,
结合发布订阅模式,给每个属性绑定 getter 和 setter,
数据变化时自动更新视图,视图变化也能更新数据。
Vue 在渲染视图时,会通过 getter 收集依赖,记录哪些组件用到了这个数据;
当数据改变时,通过 setter 派发更新,通知对应组件重新渲染。
Vue3 则是通过 Proxy 代理整个对象来实现响应式,性能更好。
缺点:
- 无法监听数组的下标修改(比如
arr[0] = 1)和长度修改(比如arr.length = 0)(Vue2 手动重写了数组的 7 个方法:push/pop/shift/unshift/splice/sort/reverse 来解决); - 无法监听对象的新增 / 删除属性(需要用
Vue.set/this.$set); - 初始化时需要遍历所有属性,嵌套对象需要递归劫持,性能较差。
这 3 种操作 Vue2 监听不到:
- 通过下标直接改
arr[0] = 100
- 直接修改 length
arr.length = 0
- 新增一个对象属性
obj.newKey = 123
这些不会更新视图。
5. Vue 的虚拟 DOM 和 Diff 算法?
解答:
- 虚拟 DOM :用 JS 对象描述真实 DOM 结构(比如
{ tag: 'div', props: { class: 'box' }, children: ['hello'] }),避免频繁操作真实 DOM。 - Diff 算法 :Vue 的 Diff 是 "同层对比"(只对比同一层级的节点),核心优化:
- key 优化:列表渲染时,key 作为节点的唯一标识,Vue 能快速判断节点是新增 / 删除 / 移动(不要用 index 当 key);
- 静态节点提升 :Vue3 会把静态节点(比如
<div>hello</div>)提升到渲染函数外部,避免每次重渲染都创建新节点; - PatchFlag:Vue3 给动态节点打标记(比如标记 "文本变化""class 变化"),更新时只遍历有标记的节点,减少对比次数。
6. Vue 组件间通信有哪些方式?
解答:按场景分类(新手易记版):
| 通信场景 | 方式 | 适用场景 |
|---|---|---|
| 父传子 | props | 基础场景(父组件给子组件传数据 / 方法) |
| 子传父 | $emit / v-on | 子组件触发父组件事件并传值(比如按钮点击通知父组件) |
| 兄弟组件 | 事件总线(Vue2)/mitt(Vue3) | 简单场景的兄弟通信 |
| 跨层级 / 全局 | Provide / Inject | 祖孙组件通信(无需逐层传递 props) |
| 全局状态 | Vuex/Pinia | 大型应用的全局状态管理(比如用户信息、购物车) |
| 任意组件 | attrs / listeners(Vue2) | 透传属性 / 事件(无需手动声明 props) |
7. 为什么不能直接修改 props?如何实现子组件修改父组件数据?
解答:
- 不能直接修改 props 的原因 :Vue 遵循单向数据流(父组件 props → 子组件),子组件修改 props 会导致数据来源混乱(父组件不知道数据被修改),难以调试。
- 实现子组件修改父组件数据的正确方式 :
- 父组件传递一个修改数据的方法给子组件,子组件调用该方法;
- 子组件通过
$emit触发父组件的自定义事件,父组件在事件处理函数中修改数据。
- v-if 和 v-show 的区别?分别用在什么场景?
| 维度 | v-if | v-show |
|---|---|---|
| 实现原理 | 动态创建 / 销毁 DOM 节点 | 控制 DOM 元素的 display 样式(节点始终存在) |
| 初始渲染 | 条件为 false 时,不渲染节点(性能更好) | 条件为 false 时,仍渲染节点(只是隐藏) |
| 切换开销 | 高(创建 / 销毁节点) | 低(仅修改样式) |
| 适用场景 | 条件很少切换的场景(比如权限控制) | 条件频繁切换的场景(比如 tab 切换、开关) |
四、路由与状态管理(高频)
1. Vue Router 的常用路由模式有哪些?区别是什么?
解答:Vue Router 有两种核心路由模式:
- hash 模式(默认) :
- 路径带
#(比如http://localhost:8080/#/home); - 原理:监听
hashchange事件,#后面的内容不会发送到服务器; - 优点:兼容性好(支持低版本浏览器),无需后端配置;
- 缺点:路径带
#,不够美观。
- 路径带
- history 模式 :
- 路径无
#(比如http://localhost:8080/home); - 原理:利用 HTML5 的
history.pushState/replaceStateAPI 修改 URL,不触发页面刷新; - 优点:路径美观,和普通 URL 一致;
- 缺点:需要后端配置(刷新页面时,服务器需返回 index.html,否则 404)。
- 路径无
2. 如何实现 Vue Router 的路由守卫?常用场景有哪些?
路由守卫是 Vue Router 提供的钩子函数,用于控制路由的跳转(比如权限校验、页面跳转前的确认),核心分类:
- 全局守卫 :
router.beforeEach:每次路由跳转前触发(最常用,比如登录校验);router.afterEach:每次路由跳转后触发(比如修改页面标题)。
3. Vuex 和 Pinia 的区别?为什么 Vue3 推荐用 Pinia?
Pinia是vue官方推荐,体积更小,写法更简单。
Vue3 推荐 Pinia 的原因:
- 语法更简洁,符合 Vue3 Composition API 风格;
- 更好的 TS 支持;
- 无 mutations 限制,开发更灵活;
- 体积更小,性能更好。
五、性能优化(加分项)
1. Vue 项目常用的性能优化手段有哪些?
组件层面:
- 用
v-show替代v-if处理频繁切换的场景; - 列表渲染加
key(唯一标识),避免 Diff 算法失效; - 缓存组件(
keep-alive):缓存不常变化的组件(比如 tab 页),避免重复渲染;
数据层面:
- 避免响应式数据嵌套过深(Vue2 递归劫持属性,嵌套越深性能越差);
- 用
Object.freeze()冻结静态数据(避免 Vue 劫持无意义的属性);
打包层面:
- 按需引入第三方库(比如 Element UI 只引入需要的组件);
- 开启 Gzip 压缩(后端配合);
- 图片懒加载(用
vue-lazyload插件)。
2. 什么是防抖和节流?在 Vue 中如何使用?
解答:
- 防抖(debounce):触发事件后延迟 n 秒执行,期间再次触发则重置延迟(比如输入框搜索、窗口 resize);
- 节流(throttle):每隔 n 秒只能执行一次(比如滚动加载、按钮点击防重复提交);单位时间内只执行一次。