ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue面试高频考点全解析:从响应式原理到性能优化实战

Vue面试高频考点全解析:从响应式原理到性能优化实战 每年金三银四之前后台私信里问得最多的就是“Vue面试题有没有整理”“有没有现成的复习资料”。我过去两年面了不下五十个候选人也帮朋友做了不少模拟面试一个很明显的感受是很多人背了一堆题但一问到原理就卡壳一写到代码就露馅。这篇东西我不打算写成面经大全而是从面试官提问的逻辑出发把Vue里面真正高频、真正能拉开差距的知识点掰开揉碎讲一遍。文章适合正在准备中级前端岗位面试的同学也适合那些用Vue写过业务但没系统梳理过原理的人——你看完不一定能背出所有答案但至少能理解面试官到底在考什么以及你自己哪里还薄弱。1. Vue面试的核心逻辑面试官到底想考察什么先说一个很多人没想明白的事。面试官问你Vue不是真的想听你背出某个API的文档解释而是想在短时间内判断三件事你写业务写了多久、你遇到问题怎么排查、你有没有主动往深处钻过。这三件事分别对应三种层次的考察方式理解了这一点你的复习方向才不会跑偏。第一层是“用过没有”对应的是基础语法题v-if和v-show区别、computed和watch区别、组件通信方式有哪些。这类题只要写过项目基本都能答上来属于送分题但也是筛掉没写过代码的人的第一道门槛。第二层是“懂不懂原理”对应的是响应式原理、虚拟DOM、diff算法、nextTick实现、key的作用这类题。这里开始有区分度了因为大部分业务开发其实接触不到这层需要你主动去看源码或者看高质量文章才能答得上来。第三层是“能不能解决问题”对应的是性能优化、异常处理、工程化配置、复杂场景设计。这一层没有标准答案面试官看你思考问题的路径是否清晰能不能给出有依据的取舍。我见过很多候选人死在第二层和第三层之间。他能把Object.defineProperty的getter和setter背得滚瓜烂熟但问他“Vue 3为什么改用Proxy”就只会说“性能更好”——这个回答不能算错但远远不够。面试官想听的是Proxy能监听新增属性和删除属性、能监听数组索引变化、不需要递归遍历对象或数组就能实现懒代理、而且规范层面比defineProperty更彻底。这种回答才能体现出你真的理解了两者的本质差异而不是看了个标题就记住了结论。所以这篇复习笔记的整体思路是先把高频考点的原理讲透再给到实战中踩过的坑最后附上一套可以照着自测的题目清单。我不保证你看完能进大厂但至少能让你在面试的时候不会被同一个问题问倒两次。2. 响应式原理Vue最核心的考点没有之一2.1 从Object.defineProperty说起Vue 2的响应式系统建立在Object.defineProperty之上这是面试必问的开胃菜。你需要能够画出这张图每个组件实例对应一个Watcher组件渲染时读取数据会触发gettergetter里把当前Watcher收集进Dep数据变更时触发settersetter通知Dep去派发更新让Watcher重新执行渲染函数。具体到代码层面Vue 2对对象做响应式处理的核心逻辑是这样的// 简化版Vue 2响应式核心 function defineReactive(obj, key, val) { // 递归处理嵌套对象 observe(val) const dep new Dep() Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { // 收集依赖将当前活跃的Watcher加入dep if (Dep.target) { dep.depend() } return val }, set(newVal) { if (newVal val) return val newVal // 新值也可能是对象需要递归劫持 observe(newVal) // 派发更新通知所有依赖此数据的Watcher重新渲染 dep.notify() } }) }这里面有几个环节面试官特别爱追问。第一Dep.target是什么Vue在渲染前会把当前要执行的Watcher设置到Dep.target上渲染完之后再重置为null这样getter里才能知道当前是谁在读取数据才能把这个Watcher收集进对应的Dep。这属于一个经典的全局状态设计理解了这个你就明白了为什么Vue 2的依赖收集是“渲染时自动收集”的不需要手动声明依赖。第二数组的响应式处理。Vue 2对数组没有用defineProperty逐项劫持而是通过重写数组的七个方法push、pop、shift、unshift、splice、sort、reverse来实现。为什么因为defineProperty监听索引的性能损耗太大而且实际业务中直接通过索引改数组的频率不高。但它也带来了很多坑比如this.list[0] xxx这种操作不会触发更新this.list.length 0也不会。面试时如果能主动把这些坑说出来会非常加分。2.2 依赖收集与派发更新的完整链路这是响应式原理里最值得深入讲清楚的部分。我把一次数据变更到页面更新之间的完整链路给你梳理一遍你在复习的时候可以自己在草稿纸上画一遍能不看资料画出来才算真正掌握了。第一步组件初始化时Vue会对data中的每个属性调用observe递归创建Observer实例让每个属性都变成响应式的。第二步组件挂载时创建WatcherWatcher会执行一次渲染函数渲染函数读取模板中用到的数据触发数据的getter。第三步getter里调用dep.depend()把当前Watcher收集到该数据对应的Dep订阅者列表里。这里要注意一个数据可能被多个组件读取所以Dep里存的是一个Watcher数组一个组件也可能依赖多个数据所以一个Watcher也会被收集到多个Dep中是一个多对多的关系。第四步当某个数据被重新赋值时触发settersetter调用dep.notify()遍历Dep里的所有Watcher调用每个Watcher的update方法。第五步Watcher的update方法并不会立刻触发重新渲染而是会把自身加入一个异步队列等本轮事件循环的微任务阶段统一执行这就是nextTick的由来。这里有个问题值得深入思考为什么Vue 2要设计成异步批次更新而不是数据一变就立刻更新DOM因为一次交互里可能连续修改多个数据如果每次都同步重新渲染性能损失太大。Vue的做法是把同一轮事件循环内触发的所有Watcher去重后收集起来统一在微任务里执行一次渲染。这也解释了为什么修改数据之后不能立刻拿到更新后的DOM必须等nextTick回调——你拿到的DOM还是旧的。2.3 Vue 3的Proxy到底改了什么Vue 3把响应式系统重写了一遍核心是用Proxy代替defineProperty这一点基本是面试必问了。你需要能讲清楚两个层面Proxy解决了Vue 2的哪些痛点以及它带来了哪些新的东西。Vue 2的痛点主要包括无法监听新增属性和删除属性需要Vue.set和Vue.delete来弥补对数组索引和length的变化无能为力初始化时就要递归遍历所有属性做响应式处理对象越大损耗越大。Proxy完全解决了这些问题因为它代理的是整个对象而不是对象上的某个具体属性所以新增、删除、读取、写入、遍历都能被拦截到而且不需要在初始化时就递归遍历——真正访问到某个嵌套对象时才在get里懒触发reactive继续代理性能和内存占用都有明显改善。但Proxy也有它自己的约束。比如Proxy返回的是代理对象比较时和原对象不相等比如this的指向问题用Reflect访问属性才能保证getter里的this指向正确。这些细节如果你能说出来面试官对你的源码功底会非常认可。// 简化版Vue 3响应式核心 function reactive(target) { return new Proxy(target, { get(target, key, receiver) { const res Reflect.get(target, key, receiver) // 懒代理访问到嵌套对象时才继续做响应式 if (typeof res object res ! null) { return reactive(res) } track(target, key) return res }, set(target, key, value, receiver) { const result Reflect.set(target, key, value, receiver) trigger(target, key) return result }, deleteProperty(target, key) { const result Reflect.deleteProperty(target, key) trigger(target, key) return result } }) }2.4 面试追问与加分回答关于响应式面试官一般会有几个追问方向我提前列出来你自己先答一遍试试。第一个追问data里不声明直接this.xxx 1Vue 2中页面会更新吗答案是不会因为实例化之后才做双向绑定你没在data里声明属性就没有经过defineProperty劫持。Vue 3中也不会但原因变了——Proxy代理的是初始对象后来加的属性也能被捕获但Vue 3的模板渲染依赖effect收集没在渲染时读取过的数据不会建立依赖关系所以同样不会触发更新。第二个追问Vue 2中$set是怎么实现的对对象来说是Object.assign做一次属性拷贝重新触发setter对数组来说是用splice方法触发数组的重写方法。第三个追问为什么Vue 3的响应式更好但有些场景还需要ref这其实是API设计的问题。reactive只能代理对象基本类型值无法直接用Proxy所以设计了一个ref包装器用{ value: xxx }的形式把基本类型包装成响应式对象。模板里的ref会自动解包所以不用写.value但JS逻辑里必须写。这个设计常被吐槽但面试时说出来会让对方知道你真的写过Vue 3。3. 组件通信所有框架面试都绕不开的题3.1 八种通信方式对比组件通信是Vue面试题里的常青树几乎每一轮技术面都会问。我把实际开发中用得上的通信方式整理成了一张表你可以对照着看一眼自己有哪些没掌握。通信方式使用场景特点与注意点props / emit父子组件传值最基础最常用props单向数据流子组件不能直接修改propsv-model父子组件双向绑定语法糖本质是props emit的封装ref / $refs父组件直接操作子组件实例适合简单场景但破坏了组件封装性不推荐频繁使用$parent / $children跨级访问Vue 3中$children已移除不推荐provide / inject祖先组件向任意后代注入适合跨层级共享但数据流不透明需要约定规范$attrs / $listeners组件透传属性Vue 3中合并为$attrs常用于二次封装UI组件EventBus / mitt任意组件通信Vue 3中EventBus被移除推荐用mitt注意要清理监听Vuex / Pinia全局状态管理适合多组件共享、有复杂交互逻辑的场景面试的时候不要只把表背出来你要能结合场景说明你怎么选。比如我会说如果只是父子传值props/emit就够了强行上Vuex是过度设计如果是跨三层以上的共享状态用provide/inject虽然方便但调试困难我会优先考虑Pinia如果是一个全局的登录状态和用户信息那必须用Pinia因为要支持时间旅行调试和模块化拆分。这种基于场景的取舍判断才是面试官想听的东西。3.2 v-model的本质v-model这个语法糖很多新人都以为它是框架魔法但实际上它就是一个简写。在Vue 2中组件上的v-model等价于绑定了valueprop和input事件在Vue 3中改了默认绑定的prop名是modelValue事件是update:modelValue。所以你在自定义组件上要支持v-model就必须接收对应的prop并emit对应的事件。Vue 3还支持v-model绑定多个值比如一个组件上可以同时写v-model:title和v-model:content这是通过给v-model加参数实现的。这个特性在做表单类复合组件时非常有用比如一个地址选择器需要同时对外暴露省、市、区三个值你就可以用三个带参数的v-model而不是把一个对象拆来拆去。我实操中的一个建议是封装组件时尽量不要直接对props里接收的值做修改而是通过emit通知父组件去改否则很容易出现“数据流断裂”的问题。你可以在子组件里用computed包一层get取props的值set里emit更新事件这样外部看起来就是一个正常的双向绑定template input v-modellocalValue / /template script setup const props defineProps({ modelValue: String }) const emit defineEmits([update:modelValue]) const localValue computed({ get() { return props.modelValue }, set(value) { emit(update:modelValue, value) } }) /script这个模式是自定义组件支持v-model的标准写法务必要在面试前亲手写一遍。3.3 插槽与作用域插槽插槽也是组件通信的一部分只不过它通信的不是数据而是模板内容。默认插槽和具名插槽都比较基础难点和作用域插槽。作用域插槽的核心是父组件在使用子组件时能从子组件那里拿到数据来定制插槽里的内容。举个例子你写了一个表格组件表格内部自己处理了数据排序和分页但需要让使用者可以自定义每一列怎么渲染。这种情况下你就需要把当前行的数据通过作用域插槽暴露出去子组件里写slot :rowrow :indexindex /父组件里用template #default{ row, index }来接收。这样父组件拿到row对象就可以任意定制单元格内容了。Vue 3中的插槽还有一个小变化$scopedSlots被移除了统一用$slots而且模板里默认插槽和具名插槽的API被统一了。我在项目里遇到过Vue 2迁移到Vue 3时插槽相关代码大量报错的情况建议复习的时候留意一下。4. 生命周期与路由高频题与隐藏考点4.1 生命周期调用顺序详解生命周期是Vue面试的基础题但我发现很多人只是机械地背名字对“父子组件的生命周期顺序”“异步组件和keep-alive对生命周期的影响”这些问题完全没有概念。而这些才是面试中真正用来区分水平的问题。先看基础版。Vue 2的生命周期包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed加上activated和deactivated两个配合keep-alive的生命周期。Vue 3中destroyed改名成了beforeUnmount和unmounted。你需要知道每个阶段能做什么created时可以访问data但拿不到DOMmounted时DOM已经挂载完成可以操作DOMbeforeUnmount里要做清理工作比如解绑事件和清除定时器。再看进阶版——父子组件生命周期顺序。父组件执行beforeCreate、created、beforeMount之后开始挂载子组件子组件依次执行beforeCreate、created、beforeMount、mounted等子组件挂载完了父组件才执行mounted。也就是说挂载阶段是“父-子-父”创建和挂载交叉进行。销毁阶段正好相反父组件先触发beforeDestroy然后子组件开始销毁等子组件销毁完父组件才执行destroyed。这个顺序你在面试时如果能脱口而出面试官就知道你确实调过接口排查过问题。4.2 路由守卫与权限控制路由这块面试最常见的问题是路由守卫有哪些、执行顺序是什么、路由权限控制怎么做。路由守卫分三类全局守卫beforeEach、beforeResolve、afterEach、路由独享守卫beforeEnter、组件内守卫beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。执行顺序是全局beforeEach - 路由独享beforeEnter - 组件内beforeRouteEnter - 全局beforeResolve - 全局afterEach。权限控制几乎是每个中后台项目都必须实现的功能也是一个非常好的面试素材。我在项目里常用方案是路由表拆成两部分一部分不需要登录就能访问的公开路由比如登录页、注册页、404页另一部分是需要权限才能访问的动态路由。用户登录后后端返回该用户的权限标识或角色前端根据这个标识通过addRoute动态注册路由。这里有个很容易踩的坑动态添加的路由在刷新页面后会丢失因为前端路由表是在内存里的。解决方式是刷新后重新获取用户信息、重新算一遍动态路由再addRoute。另外一个坑是如果你把/重定向到/home但动态路由还没注册刷新时会先匹配到重定向然后发现没有匹配的路由跳转到404。解决办法是把重定向设置成一个函数判断当前用户信息和路由表状态或者干脆不配重定向在首屏加载完成后再跳转。4.3 动态路由与keep-alivekeep-alive是面试里和路由深度绑定的话题。它本身是Vue内置的一个抽象组件作用是缓存组件的状态让组件在切换时不被销毁。我们通常把需要缓存的页面组件包在keep-alive里配合include和exclude指定哪些组件缓存。如果你在做后台系统希望切换tab时保留表单填写的内容就需要用到它。但有个隐藏考点动态路由和keep-alive的组合会出现缓存失效的问题。因为keep-alive的include匹配的是组件名称而不是路由名称。如果动态路由的组件名称不固定或者没有给组件设置name属性缓存会失效。另一个隐藏考点是keep-alive缓存了多个组件时你会看到组件从A切到C再从C切回A时A还是之前的状态——这个“状态保持”在面试题里经常被拿来和普通组件生命周期做对比你要能准确说出被缓存组件切换时只触发activated不会触发mounted。5. 源码级与实战型面试题精选5.1 key的作用虚拟DOM复用的关键key也是面试超高频题。很多人只知道“列表要加key用index会有问题”但说不出原理。我会这样回答Vue的diff算法在进行同层比较时通过key来判断新旧节点是否是同一个节点。如果key相同Vue会认为这两个节点是同一个可以复用DOM节点只做属性的更新如果key不同就会销毁旧节点、创建新节点。key的作用是给虚拟DOM一个唯一标识让diff算法能够精准地复用而不是靠遍历猜测。那为什么用index做key会出问题因为数组去重或重新排序时index会变化导致新旧节点的key对应关系错乱明明只是位置变了Vue却不知道它们原本是同一个节点就会走销毁重建的流程性能反而变差。更严重的是如果列表项里有输入框用index做key还会导致状态错乱——比如原本第一行输入了内容排序后内容跑到了别的行上。这是实际开发里非常经典的一个坑几乎每个面试官都会追问一句“为什么用index会有问题”你把上面这段说清楚就够了。5.2 nextTick原理Vue为什么拿不到最新DOMnextTick是另一个面试高频点。一句话解释Vue更新DOM是异步的修改数据后你同步去拿DOM拿到的还是旧值nextTick可以在DOM更新完之后执行回调让你拿到最新值。原理层面Vue 2的nextTick实现是做了兼容降级的异步策略优先用Promise.then微任务不支持就用MutationObserver再不行就用setTimeout宏任务。Vue 3因为不兼容IE了直接使用Promise.then。设计上用微任务而不是宏任务的原因很简单微任务在当前事件循环结束后立即执行比宏任务更快用户拿到新DOM的延迟更低。这里需要理解一个关联数据变更 - setter触发 - watcher进入异步队列 - 微任务统一执行渲染 - 渲染完DOM更新。nextTick的回调会被插到这个异步队列的末尾所以执行时DOM已经更新完了。如果面试官问“nextTick和setTimeout有什么区别”你可以说在Vue更新DOM这个场景下nextTick的时机比setTimeout更早更可靠因为setTimeout是宏任务要等微任务执行完才执行层级上就晚了。5.3 性能优化首屏加载、列表渲染与组件拆分性能优化是初中级面试里最接近真实工作场景的题。我总结几个我在项目里实测有效的方向每个都可以展开讲。首屏加载优化。最常见的手段是路由懒加载把首屏不需要的页面拆出去用动态import的方式按需加载。配合vite或webpack的代码分包可以显著减少首屏JS体积。还有一个容易被忽略的优化点是图片懒加载对于长列表和长页面用loadinglazy或者封装一个自定义指令减少首屏请求量。列表渲染优化。大列表要配合虚拟滚动只渲染可视区域内的数据。这个方案在几百条数据时看不出来差别但几千条甚至上万条时DOM节点数量会直接影响渲染和交互性能。虚拟滚动的实现原理不算复杂一个容器内通过计算可视区域的高度和每行的高度动态计算出应该渲染哪几条数据然后通过translateY来撑起整体高度。面试时能画出这个模型实战能力就立住了。组件拆分和computed缓存。computed有缓存依赖不变就不会重新计算适合做复杂计算method每次渲染都会重新执行不适合做重计算。组件拆分的意义在于缩小响应式数据的依赖范围避免一个数据变化导致整个大页面全部重新渲染。这些都属于“写代码时就要考虑性能”的范畴而不是等上线后再拿性能工具去看。5.4 Vue 2迁移Vue 3的差异清单如果你简历上写了“熟悉Vue全家桶”却说不清楚Vue 2和Vue 3的差异这是非常扣分的。我整理了一份我在实际迁移中遇到过的差异清单你复习时可以对照自查。API层面的差异包括全局API从Vue.xxx变成了app.xxx比如Vue.use变成app.useVue.component变成app.component过滤器filters被移除了官方建议用computed或method替代$on、$off、$once被移除EventBus要用外部库mitt实现v-model的prop和事件名改了组件上可以绑多个v-model。模板层面的差异v-for和v-if同时使用时Vue 2中v-for优先级更高Vue 3中v-if优先级更高这会导致代码行为不同迁移时必须注意。响应式API层面的差异最大Vue 2的选项式API和Vue 3的组合式API是两种不同的组织逻辑组合式API的核心是setup函数、ref、reactive、computed、watch这些API需要你重新组织业务的思考方式。很多从Vue 2转Vue 3的同事一开始很不适应但用顺手之后很难回去因为逻辑复用和代码组织确实更清晰。面试时如果被问到“你更喜欢哪个”别只说偏好要给出具体理由。6. 项目工程化与播放器实战Vue面试里的加分项6.1 环境搭建最容易翻车的几个地方说到Vue安装和工程化很多面试题里不会直接问“怎么创建项目”但会问“你在项目里怎么配置环境”“遇到过什么环境问题”。这里我分享几个实操中高频的痛点。用vite创建Vue 3项目时Node版本必须大于等于12.2.0最好用LTS版本。很多人用nvm装了多个Node版本项目装依赖时报EBADENGINE或ERR_OSSL_EVP_UNSUPPORTED错误基本都是Node和vite版本不匹配导致的。另一个很常见的问题是装依赖时用了npm install然后依赖锁定文件冲突导致启动失败我的习惯是团队统一用pnpm配好.npmrc和packageManager字段减少环境差异。还有一个很多人忽略的细节vite在开发模式下对依赖的预构建。vite dev第一次启动时会把ESM依赖预打包到node_modules/.vite目录下面。如果你改了某些依赖的版本或者自动更新了依赖但没有重启dev server会出现页面一直报错的情况。遇到这种问题清掉node_modules/.vite缓存目录重启就好。这种问题在面试时提一嘴能让面试官觉得你真的在项目里折腾过而不是只写过demo。6.2 播放器与m3u8流媒体处理其实藏着不少面试点热搜词里有“vue播放m3u8”这个点很有意思因为很多人可能不知道它和Vue面试有什么关系。但如果你在简历里写过“video播放器”“直播流”之类的项目经历面试官一定会追着问流媒体相关的坑。m3u8是一种基于HTTP的流媒体播放清单格式常用于直播和点播播放它需要借助hls.js这个库因为在原生浏览器的video标签无法直接播放m3u8格式只有Safari支持。在Vue项目里集成hls.js的核心逻辑是拿到m3u8地址后判断当前浏览器是否原生支持不支持就创建hls实例并绑定到video元素上。一个容易踩的坑是在组件销毁时要调用hls.destroy()否则会持续拉流导致内存泄漏。另一个坑是如果m3u8是直播流视频加载失败后要监听Hls.Events.ERROR事件判断networkDetails的错误码做重连不然用户的画面会一直卡在加载状态。script setup import Hls from hls.js import { ref, onMounted, onBeforeUnmount } from vue const videoRef ref(null) let hls null onMounted(() { if (Hls.isSupported()) { hls new Hls({ maxBufferLength: 30, liveSyncDurationCount: 3 }) hls.loadSource(https://example.com/live/stream.m3u8) hls.attachMedia(videoRef.value) hls.on(Hls.Events.MANIFEST_PARSED, () { videoRef.value.play() }) hls.on(Hls.Events.ERROR, (event, data) { if (!data.fatal) return // 断流重连逻辑这里只做简单处理 if (data.type Hls.ErrorTypes.NETWORK_ERROR) { setTimeout(() hls.startLoad(), 1000) } }) } else { // 降级处理直接赋值给video标签Safari原生支持 videoRef.value.src https://example.com/live/stream.m3u8 } }) onBeforeUnmount(() { if (hls) hls.destroy() }) /script template video refvideoRef controls playsinline/video /template这段代码面试时手撕出来配套讲清楚为什么要监听ERROR、为什么要重连、为什么要destroy绝对是一个高质量的加分项。因为这些问题在普通的CRUD业务里根本碰不到能答出来说明你做的项目有深度。7. 备考建议与常见问题排查实录7.1 一套可自测的Vue面试题清单我按照自己面试别人的习惯整理了一套自测题你可以在面试前几天过一遍能不看资料回答出百分之八十基本就稳了。基础题部分v-if和v-show的区别及使用场景v-for为什么需要keycomputed和watch的区别及各自适用场景组件通信方式有哪些ref和reactive的区别。原理题部分Vue 2和Vue 3的响应式原理差异nextTick的实现原理虚拟DOM和diff算法的作用provide/inject的实现原理keep-alive的实现原理。实战题部分列表渲染性能优化方案权限控制的实现方案组件二次封装的思路首屏加载优化措施Vue 3组合式API相比选项式API的优势。最后一次叮嘱面试官不会一道题问到底他会根据你的回答不断追问所以每个知识点你至少要准备两层深度。比如他问computed和watch区别你答了“computed有缓存watch适合异步”他大概率会追问“computed为什么有缓存怎么实现的”你如果没有准备到这一层前面的回答就成了漏洞。7.2 我踩过的一些典型的坑希望你别再踩最后分享几个我在实际项目中踩过的Vue相关的坑面试时把这些讲出来比背任何一个框架文档都有说服力。第一个坑是滥用v-if导致组件状态丢失。我在一个订单流程页面里用v-if控制步骤组件的显示切到下一步再切回来发现上一步输入的数据全没了。原因是v-if销毁了组件重建时状态归零。后来改成用v-show配合keep-alive或者用一个activeStep来控制步骤子组件的渲染问题才解决。这个坑面试官大概率也踩过你讲出来他会感同身受。第二个坑是响应式丢失。有一次我把一个对象的属性赋值给另一个变量然后在模板里直接渲染这个变量数据变了页面却不更新。排查半天才发现这个变量是直接解构出来的解构之后它就是一个普通值和响应式对象已经没有关系了。正确做法是用computed或者用toRefs来解构。这个坑在Vue 3里尤其常见因为很多人直接用reactive配合解构一解构响应式就断了。第三个坑是路由切换后页面不刷新。场景是这样的用户从列表页A进入详情页然后又在详情页里通过某种方式切换到另一个详情页此时组件会复用created和mounted不重新触发页面数据还是旧的。解决办法是给路由加:key$route.fullPath或者用watch监听路由参数的变化重新拉数据。这个坑几乎每个路由跳转比较复杂的项目都会碰到面试时说出来的含金量不亚于一个原理题。7.3 万一遇到完全不会的问题怎么办这是面试心态层面的问题很多技术不错的人挂在上面。我的建议是技术问题不会可以理解但千万不要编。你说“这个点我没深入研究过但我能从XXX角度推测一下”这个回答比硬编一个错误答案好得多。因为面试官判断的不只是你知道什么还判断你面对未知问题时是什么反应。有一个小技巧如果你答不上来可以试着把问题往你熟悉的方向引导。比如面试官问Vue 3的编译优化细节你没看过这部分源码但你知道diff算法你可以说编译器优化这块我还没细看源码但我理解虚拟DOM的diff和静态标记的工作原理从应用层来看Vite构建和按需编译对开发体验的提升非常明显。能自圆其说让面试官看到你的思路是清晰的比尬住强得多。我自己在面试时也经常用这种方式考察候选人先问一个基础题然后顺着对方的回答往深挖两步看他能不能招架住。很多人第一步回答很好第二步开始含糊第三步就露馅了。所以你在复习时不要只背第一层答案每个高频知识点都要准备到第三层的深挖。8. 写在最后的一点经验复习Vue面试题这件事最忌讳的是刷题式学习今天背了明天忘。我自己这几年的经验是与其把几十篇面经背下来不如挑几个核心主题自己动手写demo把原理搞清楚。你把响应式原理写一遍、把v-model的源码写一遍、把动态路由的权限控制写一遍比你背一百道题都有用。面试官不傻你是真懂还是记了个结论他顺着问两句就知道了。另一个感受是面试准备不要只盯着Vue本身你的JavaScript基础、异步编程、设计模式、HTTP知识都会在Vue的追问环节被带出来。响应式原理问到深处就是Object.defineProperty和Proxy的JS语法题nextTick问到深处就是事件循环的宏任务微任务路由守卫问到深处就是异步函数的执行顺序。Vue只是壳壳下面的还是基本功。最后分享一个我后来才想明白的道理面试不是考试是双方匹配的过程。你不需要所有题目都会但你展示出来的技术深度和学习能力决定了对方愿不愿意和你成为同事。把这篇笔记里提到的每个知识点吃透你拿offer的概率不会低。祝顺利。
返回列表