十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Vue3面试核心知识地图:从响应式原理到组件通信与性能优化指南

Vue3面试核心知识地图:从响应式原理到组件通信与性能优化指南 1. 先别急着背题vue面经的备考思路才是关键这两年前端面试卷得厉害vue作为国内使用率最高的框架之一基本是面试绕不开的一环。我前前后后以面试官和候选人两种身份经历了上百场与vue相关的面试最大的感受是多数人不是不会而是学得太散面得太乱。有人能把vue-router的源码背得滚瓜烂熟却说不清楚computed和watch在真实业务里的取舍有人天天用vue3却连setup的执行时机都答不利索。这篇面经不打算给你罗列一堆背诵版答案而是想跟你聊聊我在实际面试和项目里反复验证过的vue知识地图。我会把面试中真正高频的核心考点、容易踩坑的细节、以及面试官真正想听到的回答思路拆开来讲。不管你是刚入门vue的应届生还是有两年经验想跳槽的进阶开发者这篇文章都值得你花二十分钟认真看完。先把我梳理的vue面试知识地图放在前面后面所有内容都围绕这张地图展开知识模块高频考点面试常见问法重要程度响应式原理Proxy/defineProperty、依赖收集、派发更新vue3为什么用Proxy替代defineProperty极高生命周期各阶段执行时机、父子组件顺序created和mounted之间发生了什么极高组件通信props、emit、provide/inject、v-model跨层级组件通信你怎么做极高计算属性与侦听器computed缓存机制、watch深度监听computed和watch怎么选高路由机制hash/history、路由守卫、路由参数传递页面刷新后路由参数丢失怎么办高状态管理Pinia/Vuex、模块化、持久化为什么推荐Pinia而不是Vuex高diff算法虚拟DOM、patch过程、key的作用key为什么要用唯一id而不是index中高工程化组件库二次封装、性能优化、微前端你们项目是怎么做性能优化的中这张表基本覆盖了我面试中被问到的绝大多数问题。接下来我按重要程度逐个拆解每个部分都会配上我自己的真实踩坑经历和面试官视角的评分标准。2. 响应式原理vue面试的必考题答好这一题就赢了一半2.1 从defineProperty到Proxyvue3到底改了什么vue2的响应式核心是Object.definePropertyvue3换成了Proxy。这个问题几乎每场面试都会出现但大多数人的回答停在Proxy性能更好、能监听新增属性这个层面。面试官其实想听到更深的东西——你理解不理解这两种方案的本质差异。defineProperty是一把手术刀它需要在初始化时就明确知道要拦截哪些属性然后逐个把数据对象的属性变成getter/setter。这带来两个先天缺陷第一对象新增属性和删除属性时拦截器不会自动生效所以vue2才需要Vue.set和Vue.delete这种补丁API第二通过下标修改数组时defineProperty也拦不住vue2只能通过重写数组的七个方法来曲线救国。Proxy则完全不同它拦截的是对对象的操作而不是对象的某个属性。只要你是对目标对象的任何属性进行读或写都会被Proxy捕获。这就把vue2里那些补丁API全部省掉了新增属性、删除属性、修改数组下标天然支持。我在面试里遇到过一个候选人打了一个很好的比方defineProperty是给每个抽屉单独上锁Proxy是直接在房间门口装监控。这个比喻我现在还在用。从面试策略上讲你回答这个问题时最好把性能这个点说准确。Proxy确实在某些场景下比defineProperty更高效但真正的性能提升主要来自vue3的静态标记和事件缓存响应式这部分其实是功能补齐多于性能提升。能说到这个层次面试官通常就会觉得你是有实战经验而不是只背了八股文。2.2 依赖收集与派发更新一张图讲透原理响应式的核心机制是谁用到了某个数据数据变化时就通知谁。vue3里用WeakMap、Map和Set三层结构来管理依赖关系。我一般习惯用一个生活化的例子来理解Dep就是一张关注名单某个数据一旦变化它就把名单上所有关注者副作用函数effect逐一通知到。具体执行是这样一个流程初次渲染时组件会执行render函数读取响应式数据此时触发Proxy的get拦截。在get拦截里当前正在执行的副作用函数会被收集到对应数据的依赖集合中这就完成了订阅。数据被修改时触发set拦截从依赖集合里取出所有订阅者逐个执行它们的更新函数。更新函数里如果又读取了其他数据那这些数据也会被记录下来形成动态的依赖关系。这里有一个容易被忽视的点组件的render函数本身就是一个effect。vue3里每个组件实例都对应一个reactiveEffect当组件依赖的数据变化时重新执行render函数生成新的虚拟DOM再走diff更新。所以组件级更新是vue框架层面的天然机制你在写业务代码时不需要关心我要更新哪一块只需要改数据即可。我还遇到过面试官追问那模版里没用到的数据变化会触发更新吗答案是不会。因为只有在render函数执行时被get拦截访问到的数据才会被收集进依赖集合。如果你在模版里压根没用某个变量它就没有订阅者数据变化时自然也不会有任何组件被通知。这也是为什么vue3提供了手动ref和shallowRef等API来做更精细的依赖控制。2.3 新手最容易翻车的不要用index作为keykey的问题同时涉及响应式原理和diff算法是高频中的高频。很多刚接触vue的朋友不理解为什么用index作为key会有问题。我用一个极其常见的表格场景来解释假设你有一个列表渲染出三条数据每条数据对应一个输入框。如果用index作为key当你在第一行输入了内容、然后删掉第一行数据时vue的diff算法会认为第二行的key从1变成了0第三行的key从2变成了1它不会复用原来的DOM节点而是把现有的节点全部重新渲染。结果就是你在第一行输入的内容跑到第二行去了整个UI全乱了。用唯一id作为keyvue就能精确定位到哪一条数据被删除了只需要移除对应的那个DOM节点其他节点原样复用。这个问题的本质是key是虚拟DOM复用的依据它必须和数据本身绑定而不是和数据的位置绑定。面试里你能把这个例子讲清楚比背十遍key要唯一都有用得多。3. 生命周期与组件通信vue面试的主战场3.1 生命周期执行顺序面试官最爱问的父子组件联动生命周期考察的不是背诵而是你对组件渲染过程的理解。父子组件的生命周期执行顺序是典型的陷阱题很多工作了两三年的开发者都说不完整。完整的顺序是这样的父组件beforeCreate、父组件created、父组件beforeMount、子组件beforeCreate、子组件created、子组件beforeMount、子组件mounted、父组件mounted。更新阶段也是同理父组件beforeUpdate、子组件beforeUpdate、子组件updated、父组件updated。销毁阶段父组件beforeUnmount、子组件beforeUnmount、子组件unmounted、父组件unmounted。这个顺序背后的逻辑其实很好理解父组件的模版里引用了子组件所以父组件必须先完成自己的数据初始化created才能去渲染模版、发现子组件、触发子组件的创建。而子组件必须先完成自己的挂载父组件的挂载才算真正完成因为父组件的DOM里包含了子组件的DOM。我踩过一个真实的坑在一张复杂的报表页面里我在父组件的mounted里调用了接口获取数据然后通过props传给子组件渲染图表。但子组件的mounted比父组件先执行这时候props还是空的图表初始化拿不到数据。后来我把接口调用挪到了created里或者用watch监听props变化再初始化图表问题才解决。这种实战经验在面试里讲出来比单纯背顺序值钱多了。v-if和v-show对生命周期的影响也是常考点。v-if为false时组件压根不会创建mounted不会执行v-show为false时组件已经创建并挂载了只是display:none。这对性能优化和业务逻辑都有影响比如轮播图组件你希望它隐藏时也能保持状态就该用v-show如果用v-if切换组件状态会全部丢失。3.2 组件通信方式全梳理从props到provide/injectvue的组件通信方式非常丰富面试一般会问你你们项目里都用过哪些通信方式。我把它们按使用场景排个序props和emit是最基础、也最常用的一对。父组件通过props向子组件传数据子组件通过emit事件通知父组件。这里要注意props是单向数据流子组件不应该直接修改props的值否则会触发警告。如果你确实需要修改正确的做法是通过emit让父组件改或者是用computed包装一层。v-model本质上是props和emit的组合语法糖。在vue3里v-model可以绑定多个值v-model:title和v-model:content可以共存底层分别对应title属性和update:title事件。封装表单类组件时这个技巧特别实用你可以让一个组件同时管理多个字段。provide和inject解决的是深层嵌套通信问题。比如你的根组件提供了一个userInfo对象无论中间隔了多少层组件任何子孙组件都能通过inject拿到它。这在大项目里能省掉很多逐层透传的痛苦。但面试里你要能主动说出它的缺点provide和inject不是响应式的除非你传的是ref对象而且会让组件之间的依赖关系变得隐蔽不利于维护。所以它能解决跨层通信但别滥用。eventBus在vue2时代很流行但在vue3里已经不太推荐了官方更建议用mitt这种独立的事件库。让我印象很深的一个案例有个项目里eventBus的事件在组件销毁时没解绑导致页面频繁切换后事件重复触发请求被发了七八次。从那时起我就建议团队全面转向provide/inject加Pinia的组合。4. computed与watch看似简单实则暗藏杀机4.1 computed的缓存机制你真的理解了吗computed的缓存机制是老生常谈但很多人理解得不彻底。computed会基于它的响应式依赖进行缓存只有依赖的数据发生变化时才会重新计算否则每次访问都直接返回之前计算的结果。这个特性在性能敏感的场景下非常有用。举个例子一个表格有1000条数据每行都需要计算含税价格 原价 * 税率 运费如果写成methods里的函数每次渲染都得重新算一遍写成computed只要数据没变渲染多少次都是直接读缓存。数据量小的时候感知不强数据量一大差距就出来了。但computed有一个注意点它默认是懒执行的。只有当模版中访问到computed属性时它才会去计算。如果你在一个computed里写了复杂的逻辑但模版里没用到它是不会执行的。另外computed里不应该有副作用操作比如修改其他数据或者发请求。从设计上讲computed应该是纯函数输入相同输出永远相同。如果你需要在数据变化时做一些额外操作应该用watch。4.2 watch的deep和immediate以及和computed的取舍watch用于监听数据变化并执行副作用操作比如防抖搜索、路由变化响应、数据变化后重新请求接口等。两个常用配置项是deep和immediatedeep用来深度监听对象内部的变化immediate表示是否在初始化时就执行一次回调。deep监听有个性能隐患它内部会递归遍历对象的每个属性对象一旦很大性能消耗很可观。所以能用computed解决的就不要用deep watch。我在实际项目里更推荐的做法是明确监听对象的某一个属性比如watch(() userProfile.name, handler)而不是watch(userProfile, handler, { deep: true })。前者只在name变化时触发后者任何属性变了都会触发。computed和watch的取舍我的答案一直很明确能用computed解决的绝不用watch。computed会把数据依赖关系显式地写在声明里可读性高还有缓存watch更适合数据变化后需要执行异步或开销较大的操作这种场景。面试时如果你能列举出一个具体的取舍案例比如我需要根据购物车列表实时计算总价用computed我需要监听搜索关键词变化然后防抖请求接口用watch基本一答一个准。5. 路由与状态管理跳出会用层面说出为什么5.1 路由模式怎么选页面刷新后参数丢失怎么办vue-router的hash模式和history模式是面试必问的基础题。hash模式通过url后面的#号来实现路由切换优点是兼容性好、不需要后端配合缺点是url不好看。history模式基于HTML5的History APIurl更美观但部署到生产环境时如果后端没有做重定向配置刷新非首页会出现404。这个问题我是有惨痛经历的。之前帮一个客户部署后台管理系统用的history模式nginx只配置了location /的root指向结果用户一刷新系统管理页面就白屏。后来才意识到需要做try_files配置把所有未知路径都重定向到index.html。如果你在面试里能主动说出这段nginx配置经验面试官会明显觉得你有真实部署经验。路由参数传递有几种方式路径参数/user/:id、query参数?id1、以及通过props将路由参数传给组件。路径参数适合做详情页这种语义化的场景query适合搜索条件这种灵活的参数。刷新页面后参数丢失的问题通常是因为参数存在内存中了。比如你在A页面把数据存在了变量里然后跳转到B页面刷新后变量没了。解决办法是把关键参数放在路由的query或路径里或者使用Pinia并配合持久化插件。路由守卫是另一个大考点。全局守卫beforeEach、路由独享守卫beforeEnter、组件内守卫onBeforeRouteLeave它们构成了一套完整的导航控制体系。实际的用途有登录鉴权未登录跳登录页、页面权限控制根据角色过滤可访问路由、页面离开确认表单未保存时弹窗提示。我在项目里用动态路由的方式根据用户权限去addRoute这个方案能精确控制每个用户能看到哪些页面比在全局守卫里做判断要优雅得多。5.2 Pinia和Vuex怎么选代码层面有什么区别Vuex是vue2时代的标配Pinia是vue3时代的官方推荐。面试时被问到两者的区别我习惯从三个维度回答。第一API设计。Vuex使用state、mutations、actions、getters四个概念其中mutations必须同步修改state只能通过commit一个mutation。Pinia砍掉了mutations修改state可以直接赋值actions里也可以同步或异步修改。少了一层概念心智负担小很多。第二TypeScript支持。Vuex的TS支持一直比较别扭因为state的响应式类型推断在某些场景下并不完美。Pinia从设计之初就为TS优化的状态定义的推断非常自然。第三代码组织。Vuex通过modules做模块划分每个模块有自己的state、mutations等嵌套层级多写法比较啰嗦。Pinia基于组合式API可以直接用setup函数的风格定义store逻辑复用更顺手。举个实际的例子同一个用户信息storeVuex要写state、mutations、actions、getters四个部分还要考虑模块注册Pinia只需要一个defineStore里面用ref定义状态、用function定义操作代码量直接减半。我最近带的一个新项目已经全面转向Pinia了连旧项目的迁移成本都不高因为两者概念上有很多对应关系。6. diff算法与虚拟DOM晋升高级前端的敲门砖6.1 虚拟DOM到底解决了什么问题很多人不理解虚拟DOM存在的意义以为它是为了比操作真实DOM更快。这个说法其实不够准确。直接操作真实DOM不一定就慢虚拟DOM的真正价值在于它把操作DOM变成了操作JS对象从而让框架能够以最小的代价进行DOM更新。你可以把虚拟DOM理解成一份DOM的设计图纸。每次数据变化时框架会重新生成一份新图纸然后和旧图纸对比找出差异只对差异部分做实际DOM操作。这个过程就是diff。它的本质是拿JS层面的计算时间换DOM层面的操作时间在大多数场景下是划算的因为浏览器里最快的是JS计算最慢的是DOM重排和重绘。vue3里diff算法的最大升级是静态标记PatchFlags。编译过程中模板编译器会给动态绑定的节点打上标记比如TEXT表示文本动态、CLASS表示class动态、PROPS表示属性动态。diff时框架只需要对比有标记的节点静态节点直接跳过这就大幅缩小了对比范围。这也是为什么vue3的渲染性能比vue2快的主要原因之一。6.2 diff过程的核心逻辑以及key在其中扮演的角色vue的diff过程核心是两个列表的对比。当新旧vnode都是数组时vue会采用双端对比的策略先从头开始对比相同就复用节点并继续再从尾部开始对比相同就复用节点并继续中间剩下的部分再用key建立映射表进行匹配。这里有个细节如果两个节点类型相同比如都是divvue会复用DOM元素只更新变化的属性或子节点如果类型不同比如一个是div一个是p会直接销毁重建。所以如果你在v-for里渲染不同类型的组件key最好能明确反映这是哪个组件否则diff很容易做无效的销毁重建。key值的作用在diff里体现得最明显。用一个具体场景来说你有一批数据用index作为key在第2个位置插入了一条新数据vue会把原来第2条数据对应的DOM节点复用给第3条数据把第3条的复用给第4条。如果这些节点内部有状态比如输入框的内容、勾选状态你看到的就会是数据错位。唯一id作为key能确保每条数据和DOM节点的对应关系稳定插入只是新增节点不会影响其他节点。从面试角度讲diff算法的问题不需要你深入源码但你必须理解虚拟DOM怎么生成、怎么对比、key为什么重要这条主线。能讲清楚这条主线配合上一两个实际案例就已经属于中上水平的回答了。7. 工程化与实战面试官真正看重的加分项7.1 路由懒加载与组件库按需引入工程化是面试里简历项目经验环节的常见话题。你写了使用vue开发后台管理系统面试官很可能会追问性能优化是怎么做的。首当其冲的就是路由懒加载。vue项目打包后如果不做任何处理所有页面的代码都会打包成一个巨大的JS文件。用户首次打开页面就得下载完整文件白屏时间长体验极差。路由懒加载通过动态import把每个页面拆成独立的chunk访问到该路由时才加载对应模块。配置方式很简单在路由表的component字段里原本写import Home from ../views/Home.vue改成const Home () import(../views/Home.vue)。组件库的按需引入也是一个效率点。很多项目用了Element Plus这类组件库如果直接全局注册打包时会把所有组件带进产物明明只用了一半的组件却额外贡献了十几KB的包体积。按需引入一般配合unplugin-vue-components插件使用它能自动扫描代码中实际用到的组件并只注册这些。我一般建议项目初始化时就把这个插件事先配好不然后期再改成本会高不少。此外还有几个实战中验证过有效的优化手段图片懒加载使用v-lazy指令或IntersectionObserver页面滚动到可视区时才加载图片。第三方库CDN化像lodash、echarts这种大型依赖用CDN引入并从打包配置里排除掉能显著减少打包体积。大数据列表虚拟滚动几千条数据一次性渲染会造成卡顿使用虚拟滚动只渲染可视区域内的节点。7.2 Hzero前端开发中的字典管理和组件的二次封装热搜词里提到了前端系统管理下的字典管理这其实是一个很经典的企业级应用场景。字典管理的意思是把项目中用到的可枚举数据比如用户状态、订单类型、审批状态统一维护在一个字典表里前端通过接口获取字典项然后在表单下拉、表格标签等场景中复用。我在实际的HZero项目里做过一个useDict组合式函数同时基于Loading状态缓存字典数据组件销毁时不重复请求。如果一个页面里三个下拉框用同一个字典就只请求一次。这个思路比每个组件各自请求一次高效得多。面试时如果能主动说出这种实践细节面试官对你的印象分会明显不一样。组件二次封装也是面试加分项。直接使用Element Plus的表格组件写业务时会发现大量重复的代码分页、loading状态、日期格式化、操作列按钮。我的做法是封装一个BaseTable组件把表格的通用逻辑loading、空数据、分页事件全部封进去业务页面只需要传columns和dataSource。这样做的好处很直接改分页逻辑只需要动一个组件而不是全站几十个页面。7.3 微前端方案的核心思路以及什么时候才需要它微前端是这两年大厂面试的高频词也是加分题。面试官一般不指望你把qiankun源码讲明白而是想确认你对前端架构拆分有没有概念。微前端的核心思路是把一个大型前端应用拆分成多个可以独立开发、独立部署的小应用由一个主应用负责统一调度。主应用维护一份路由注册表访问到某个子应用的路由时动态加载对应子应用的入口JS。那什么时候才需要微前端呢我遇到过一些团队在项目只有两三个后端管理系统的时候上微前端结果反而增加了部署和联调的复杂度。微前端真正适合的场景是多个团队各自负责一块业务版本迭代节奏不同希望独立部署互不影响。比如我之前做过的一个项目有订单、物流、售后三个子应用由三个团队分别维护主应用用qiankun做集成。这种情况下微前端是刚需因为各团队无法保证同步发版。不过微前端也带来了通信成本和样式隔离的复杂度它本质上是一种架构上的取舍。面试时你如果能主动说出这个不是银弹的立场比一味吹捧微前端明显更有说服力。7.4 前端用Worker上传大文件和视频流播放的实战经验热搜词里的前端使用worker上传大文件和vue播放m3u8都是非常实战的场景面试中如果你做过类似功能一定要重点讲过程。大文件上传的常规痛点一次性把文件塞给后端内存占用高、容易失败、失败后得重新传。我的方案是分片上传加Worker。分片上传的思路是用File.slice把文件切分成多个固定大小的块比如每块2MB每块单独上传。后端收到所有分片后合并。Worker的作用是文件切分和计算MD5校验值这些CPU密集的操作放到Worker线程里执行避免阻塞主线程导致页面卡顿。我实际测过一个500MB的文件在Worker里计算MD5主线程的滚动流畅度几乎不受影响如果用主线程算页面会有明显的卡顿。播放m3u8的做法是m3u8是HLS协议的索引文件里面存了一系列的分片ts文件地址。vue里播放时通常用hls.js库先解析m3u8再通过video标签播放。核心流程是npm安装hls.js、在播放器组件里引入、检测浏览器是否支持原生HLSSafari支持Chrome不支持、不支持时用hls.js加载。要注意的是m3u8通常涉及跨域后端需要配置CORS头否则视频加载不出来。这个坑我踩过排查了整整一个下午才发现是CORS问题。7.5 vue devtools插件调试效率的倍增器前端开发skills里最被低估的工具就是vue devtools。它在调试状态管理、组件props、路由跳转时效率比console.log高一个量级。安装方面vue3对应Vue.js devtools的V6版本一般通过浏览器扩展商店直接装。如果你在公司内网的浏览器环境装不了插件可以尝试离线安装步骤如下在GitHub的vue-devtools仓库找到对应浏览器的插件包下载crx文件。打开浏览器的扩展管理页启用开发者模式。把crx文件拖进浏览器窗口按提示完成安装。安装后重启浏览器打开vue项目页面F12会多出一个Vue Tab。使用上我调试时最常用的三个面板组件树面板查看组件的props、data、computed值直接改值测UI、Vuex/Pinia面板查看当前状态、调用actions、时间旅行、路由面板查看当前路由的所有参数。有一次排查一个某个弹窗为什么显示了错误的数据的问题就是用组件树面板定位到弹窗组件直接查看它接收的props一眼看到了数据是从父组件的旧地址传过来的五分钟定位到了问题。8. Vue3新特性与组合式API用了两年vue3这些点你未必讲得清楚8.1 setup、ref、reactive、toRefs各自的适用场景vue3的组合式API把按选项组织代码变成了按逻辑组织代码。这并不只是写法上的变化而是思维方式的变化。setup是组合式API的入口它在beforeCreate之前执行所以里面拿不到this但可以访问props和context。ref和reactive是定义响应式数据的两种方式什么时候用哪个有讲究。ref适合定义基本类型和单独的值使用时要通过.value访问reactive适合定义复杂对象直接通过属性访问。但在项目中我的习惯是统一用ref因为ref更灵活不会遇到对象深层更新丢失响应性的问题。reactive有一个鲜为人知的坑如果整个对象被重新赋值响应性就断了。比如let form reactive({a: 1})然后form {a: 2}form不再是一个响应式对象。用ref则完全没有这个问题因为.value的赋值依然走响应式拦截。toRefs用于把reactive对象的每个属性变成单独的ref这在setup返回模版变量时特别有用。比如const state reactive({name: abc, age: 18})如果你直接return state模版里用state.name。但用了toRefs(state)之后就可以在模版里直接用name和age而且保持了响应式。如果不做toRefs处理直接把state解构成name和age解构出来的值只是一个普通变量完全不响应。这个细节在面试里问出来能筛掉不少假会用的人。8.2 生命周期钩子在setup中的写法以及和选项式的对应关系vue3的组合式API里生命周期钩子都换成了onXxx的形式并且只能在setup中同步调用。比如onMounted对应mountedonBeforeUnmount对应beforeDestroyonUpdated对应updated。有几个额外的钩子是vue3新增的onRenderTracked和onRenderTriggered用于调试——前者在每次依赖被追踪时触发后者在依赖变化触发重新渲染时触发。另一个变化是setup中拿不到this所以在访问组件实例属性时需要通过getCurrentInstance()。但我要提醒一句官方并不推荐在业务代码里用getCurrentInstance因为它是为高级库场景设计的API滥用会导致代码难以维护。vue3还改了一个重要的生命周期细节beforeUnmount和unmounted取代了vue2的beforeDestroy和destroyed。如果你在vue2项目里写的是beforeDestroy到了vue3项目里要注意同步改掉。我有一次做项目升级时漏改了组件销毁时的清理逻辑完全没执行导致定时器一直跑页面内存持续增长。这种细节问题面试官也爱问你知道vue3把destroyed改成什么了吗这种看似简单的问题答不出来的不在少数。8.3 组合式API解决了什么问题什么场景真的需要它组合式API的诞生最大的动力是解决复杂组件的逻辑碎片化。在选项式API里一个功能的数据、计算属性、方法、侦听器会散落在data、computed、methods、watch四个选项里。一个大型组件有七八个功能时你要翻来覆去地在几十个选项中跳转代码的阅读和复用成本都很高。组合式API的核心是把属于同一个逻辑的东西聚在一起。比如一个登录表单组件所有的验证逻辑、提交逻辑、loading状态都可以收进一个useLogin函数里。代码上很直观逻辑上更内聚复用时只要import这个函数。我在项目里拆过一个复杂的表单组件里面同时有基础信息、地址联动、套餐选择三块逻辑之前混在一起根本没法看拆成三个组合式函数后每个函数只关心自己的一块逻辑新同事接手时阅读成本显著降低。但并不推荐所有组件都强行改成组合式API。状态很少的展示型组件选项式API反而更简洁readable code本身就是一种优势。面试时如果被问你怎么看待组合式API和选项式API能答出看场景小组件用选项式复杂逻辑用组合式这种务实态度的候选人通常会比一味鼓吹新技术的更让我满意。9. 高频面试题速查与避坑经验实录9.1 面试中重复出现的问题怎么组织自己的答案整理一下我在多次面试中遇到的高频题每个都给出我的参考思路问题参考回答思路易犯错误v-if和v-show的区别v-if是真正的条件渲染false时不渲染节点v-show是display切换节点始终存在。频繁切换用v-show运行时条件很少改变用v-if说不清楚各自对生命周期的影响vue3为什么用Proxy支持新增/删除属性、支持数组下标修改、拦截粒度更细、代码实现更简洁只会说性能更好说不清具体原因组件通信有哪些方式按props/emit、v-model、provide/inject、Pinia、eventBus兼容旧方案的顺序讲结合场景举例子只背列名没有实战案例说说computed和watch的区别computed有缓存、强调依赖声明、不适合副作用watch强调监听变化后执行操作、适合异步场景只答computed能缓存watch不能key的作用是什么虚拟DOM复用依据、保证组件状态稳定、提升diff效率。结合index的坑讲只答提高性能说不清楚背后机制data为什么必须是函数组件复用时间每个组件实例必须有独立的data副本。data如果是个对象会被所有实例共享答不出每次调用返回新对象这个根本原因路由懒加载怎么做动态import代替静态import、打包拆chunk、首屏加载优化。补充实际配置路径只答概念贴不出代码nextTick是干什么的DOM更新是异步的DOM更新完成后执行回调用于需要在更新后读取DOM的场景说不清为什么是异步的9.2 我踩过的最真实的三个坑第一个坑computed里访问props导致死循环。当时写了一个组件根据props里的配置动态生成一个计算属性结果配置是对象引用且每次渲染都被父组件重新创建computed依赖的对象每次都是新引用导致computed反复触发页面卡死。排查了半天才发现解决方案是computed里只取具体的基本属性值不依赖整个对象。第二个坑深度监听大对象导致性能严重下降。一个列表页用deep watch监听整个筛选表单对象用户每次输入一个字符watch回调就触发一次还要做接口请求页面卡得没法输入。后来改成watch具体字段和防抖问题瞬间解决。此后我在团队里立了规矩禁止对超过3层深度的对象使用deep watch。第三个坑路由切换后组件缓存导致数据不刷新。后台管理系统的列表页用户从A列表切到B列表再切回来A列表的数据还是旧的因为组件被keep-alive缓存了。当时的解决方案是使用onActivated钩子重新拉取数据同时保持keep-alive的缓存效果。这个场景很多面试官也爱问你能主动说到onActivated这个钩子说明你真的处理过这类问题。9.3 面试的最后一问可以问点什么一般面试结束前面试官都会问你有没有什么问题想问。这一问很关键不建议回答没有。好的问题能体现你的思考深度。我建议问这几个方向问团队技术栈我想了解一下咱们团队现在用的是vue2还是vue3如果方便的话升级到什么版本了这能体现你对技术选型的关注。问团队规范咱们团队有前端开发规范吗比如代码规范、提交规范这一块这能体现你对团队协作的重视。问业务方向如果入职的话我主要负责哪个业务模块这能体现你对具体工作的兴趣。问晋升体系前端团队在技术晋升上有什么规划吗这能体现你的职业规划意识。不太建议问的第一类问题是公司加班多吗这种评价性问题会给面试官留下不好的印象第二类问题是我这个岗位薪资多少这种跟HR聊的话题在技术面试环节问不太合适。10. 最后再分享一个我个人的学习方法学了这么多年前端面试过别人也被别人面试过我的体会是vue的知识点就像一个相互关联的网络你今天背一个diff算法明天学一个响应式原理看起来是零散的但只要你在真实项目里把一个数据变化到DOM更新这条链路完整地走一遍所有知识点就都串起来了。所以我建议你看面经的时候一定要边看边想这个知识点在我项目里的哪个地方出现过。比如看到computed的缓存机制想想你的购物车计算总价的场景看到路由守卫想想你的登录鉴权是怎么实现的。把知识绑定在具体的场景上面试时才能做到有话说、说得准而不是像一个背稿子的机器人。Vue这套框架说大不大说小不小但真正吃透它的人面试时的那种从容感是装不出来的。
返回列表