前端文档
浏览器相关
Css
JavaScript
Vue
Typescript
React
性能优化
AI 场景
  • Vue
  • React
退出
浏览器相关
Css
JavaScript
Vue
Typescript
React
性能优化
AI 场景
  • Vue
  • React
退出
  • vue 面试题

vue 面试题

生命周期API

Vue2Vue3
beforeCreate 挂载前❌setup(替代)
created 挂载中❌setup(替代)
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured 子组件错误捕获(setup,render,声明周期,watch/computed)
-🎉onRenderTracked (渲染依赖了谁) 调试组件
-🎉onRenderTriggered (谁触发了渲染)调试组件

keep-alive

onActivated当组件被插入到DOM中时调用
onDeactivated当组件从DOM中被移除时调用

vue-router

名字作用类型
beforeEach路由跳转前 (登录鉴权/权限校验/白名单判断)全局
beforeResolve在所有组件内守卫之后,确认跳转前(等待异步数据准备完成)全局
afterEach页面埋点 /页面标题修改全局
beforeEnter单独页面的权限控制路由独享
beforeRouteEnter进入组件前组件本身
beforeRouteUpdate路由参数变化组件本身
beforeRouteLeave表单未保存提示/弹窗确认离开组件本身

生命周期调用顺序

父子组件生命周期顺序:

挂载阶段(父 → 子 → 父): 父 setup ->父 onBeforeMount ->子 setup ->子 onBeforeMount ->子 onMounted ->父 onMounted

更新阶段(父 → 子 → 父): 父 onBeforeUpdate->子 onBeforeUpdate ->子 onUpdated ->父 onUpdated

卸载阶段(父 → 子 → 父): 父 onBeforeUnmount ->子 onBeforeUnmount ->子 onUnmounted ->父 onUnmounted

vue-router生命周期顺序:

  1. beforeRouteLeave(组件)
  2. router.beforeEach
  3. beforeEnter(路由独享)
  4. beforeRouteEnter(组件)
  5. router.beforeResolve
  6. router.afterEach

数据绑定及原理

Vue2

通过 ES5 的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM树上。

Object.defineProperty 重新定义data 中所有的属性,Object.defineProperty 可以使数据的获取与设置增加一个拦截的功能,拦截属性的获取,进行依赖收集。拦截属性的更新操作,进行通知。

初始化时 -> observer => defineProperty(ge/set) => getter:依赖收集 => setter:派发更新 => 触发:dep.notify() watcher.update() , 虚拟 DOM diff,patch

Vue2 更新流程

set
 → dep.notify
 → watcher.update
 → scheduler
 → patch

Vue3

Vue3.x改用Proxy替代Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,并且有13种拦截方法。他可以通过判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理

Proxy => reflect => effect => track/trigger

vue3更新流程

trigger
 → scheduler (job queue)
 → effect runner
 → render
 → patch

Proxy 相比于 defineProperty 的优势

对比点Vue2Vue3
响应式核心definePropertyProxy
拦截粒度属性级对象级
新增/删除 属性 数组索引❌✅
初始化性能差(递归)好(惰性)
依赖结构Dep / Watchereffect / track
TS 支持一般友好
代码体积较大更小

优化方案

  • 减少入口文件体积
  • 静态资源本地缓存
  • 开启Gzip压缩
  • 对图片进行压缩 /懒加载
  • 插件提取公共代码 splitChunks
  • 提取组件的 CSS
  • 生产禁用 SourceMap
  • 利用可视化分析工具查看代码体积
  • 路由/组件 懒加载 keep-alive 的缓存
  • 第三方插件按需引入 (vant/element,antdesign)
  • 合理的定义响应式数据(data,ref,reactive)这些,防止过多的增加getter和setter,会收集对应的watcher
  • 保证key值的唯一性
  • 防抖、节流
  • 骨架屏的使用

Vue2与Vue3的区别

对比vue2Vue3
响应式系统Object.definePropertyProxy
虚拟 DOM & 渲染机制全量 diff/双端对比编译期 + 运行期双优化 /静态提升(hoist)
API 设计optionsAPIComposition
this组件实例无this
响应式数据定义dataref/reactive toRefs(解构)
计算属性/监听器Computed/watch watchEffect(自动依赖收集)
声明周期变化Created/beforeCreatedSetup
根节点单根节点多根节点 teleport
typescript支持补丁的方式支持原生设计
生态与工程化Webpack vueXvite pinia
API变化filters $on .sync $Set $delete mixinsref reactive readonly / shallowReactive / shallowRef

key的作用

  • key是为Vue中的vnode标记的唯一id,通过这个key,diff操作可以更准确、更快速
  • diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key与旧节点进行比对,然后超出差异.

diff程可以概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明oldCh和newCh至少有一个已经遍历完了,就会结束比较,这四种比较方式就是首、尾、旧尾新头、旧头新尾.

准确: 如果不加key,那么vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug. 快速: key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1).


Webpack与Vite区别

类型vitewebpack
设计目标极致开发体验强大的模块打包能力
开发服务器基于 bundle基于原生 ESM
启动流程全量构建启动serve,按需加载
模块加载打包后统一加载浏览器按需加载
热更新重新构建chunk(影响整个依赖链)模块及更新
打包引擎JSRollup
JS变异babelesbuild
cssStyle-loader css-loader file-loader 配置postCss原生支持 impot图片 自动读取

vuex与pinia的区别

纬度VuexPinia
设计思想单一store + 模块多Store天然拆分
编程方式Options APIcompoostion API
约束类型强约束(必须通过mution修改state)少约束,组合式 可直接对state进行修改或者action修改state
TS类型推导弱强
模块互调繁琐直接import

Hook的作用

hooks 是函数的一种写法。

vue3 借鉴 react hooks 开发出了 Composition API ,所以也就意味着 Composition API 也能进行自定义封装 hooks。

vue3 中的 hooks 就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。其实 hooks 和 vue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。


vue3中响应状态定义方式

API可接收类型是否响应式响应深度是否需 .value解构是否丢失响应主要用途
ref基本类型 / 对象✅深JS 中需要❌ 不丢单值状态
reactive对象 / 数组✅深❌✅ 会丢复杂对象
computedgetter / getter+setter✅深JS 中需要❌派生状态
readonly对象✅(只读)深❌—状态保护
shallowReactive对象✅浅❌✅ 会丢性能优化
shallowRef任意✅浅JS 中需要❌大对象
toRef对象属性✅继承源对象JS 中需要❌单属性解构
toRefs对象✅继承源对象JS 中需要❌多属性解构
markRaw任意❌无❌—跳过响应式

Vue 的模板是如何变成 DOM

Vue 会先把 template 编译成 render 函数,render 函数返回 虚拟 DOM,再通过 patch 过程生成真实 DOM。

template → AST → render → vnode → patch → DOM


Vue3 diff 算法有哪些优化

Vue3 在 diff 中引入了 Block Tree 和最长递增子序列(LIS),减少不必要的 DOM 移动。 PatchFlag 静态提升 Block Tree


Proxy 能监听哪些操作

get:读取属性

set:设置属性

has:in 操作符

deleteProperty:删除属性

ownKeys:Object.keys defineProperty

数组索引 / length 修改


组件通信方式

  • props / emit
  • Expose/ref
  • Provide/inject
  • Pinia/vuex
  • 事件总线(mitt)
  • Slot/scoped slot
  • 路由参数
  • 全局状态/URL

Vue Router核心原理

一句话核心答案(先说结论):

Vue Router 的核心实现原理是:监听 URL 变化 → 通过 matcher 匹配路由 → 将当前路由变成响应式状态 → 驱动 <router-view> 渲染对应组件,而整个过程不刷新页面。

监听 URL 变化:

  • Hash 模式:通过 window.addEventListener('hashchange', ...) 监听 URL 中 # 后面的部分变化,兼容性好,不包含在 HTTP 请求中。
  • History 模式:利用 HTML5 的 history.pushState 和 history.replaceState API 修改 URL,并通过 popstate 事件监听前进后退。
  • abstract模式:利用数组栈的思想实现。Vue Router 的 abstract 模式不依赖浏览器 history,而是用一个数组 stack + index 指针,在内存中模拟浏览器历史栈,通过 push / replace / go 操作数组来完成路由前进、后退与替换,常用于 SSR 和测试环境。

React 与 Vue 详细对比

对比维度ReactVue
设计理念函数式编程,组件即函数渐进式框架,组件即配置对象
数据流单向数据流(自上而下)双向数据绑定(v-model)
核心思想声明式 UI,虚拟 DOM响应式系统,模板编译
更新机制手动 setState 触发更新自动追踪依赖,自动更新
不可变性强调不可变数据支持可变数据,自动处理
函数式编程强烈推荐,Hooks 基于函数式支持但不强制,更灵活
模板语法JSX(JavaScript 扩展)HTML-like 模板语法
计算属性useMemo()computed()
副作用useEffect()watch(), watchEffect()
响应式原理手动触发更新(setState)自动依赖追踪(Proxy/Object.defineProperty)
组件缓存React.memo()v-memo 或 keep-alive
计算缓存useMemo()computed() 自动缓存
函数缓存useCallback()自动优化
最近更新: 2026/2/7 15:43
Contributors: milly980810@gmail.com, weak