前言
上周面了个应届生,简历上写着"熟悉Vue框架,有多个项目经验"。我问他v-if和v-show的区别,他说"一个是显示隐藏,一个是条件渲染"。我追问"那什么场景用哪个",他卡壳了,这就是典型的'背题党'。
这就是大部分人的现状:概念背得滚瓜烂熟,一问实战场景就露馅。
今天这10道Vue基础题,每道题我都会告诉你:面试官为什么问这个、标准答案怎么说、什么回答会让你直接出局。每题都配"速记公式",面试前一晚看这篇就够了。
1. 什么是Vue.js?Vue的核心特性和设计理念是什么?
速记公式:渐响组模,虚指易学
(渐进式、响应式、组件化、模板语法 + 虚拟DOM、指令系统、易学)
标准答案
Vue是一个渐进式JavaScript框架,用于构建用户界面。它的设计理念是自底向上增量开发,你可以只在页面的某个部分使用Vue做数据绑定,也可以配合Vue Router、Vuex等全家桶构建完整的单页应用。
核心特性主要有几个方面:
首先是响应式数据绑定,当你修改data中的数据时,视图会自动更新。这是通过Vue的响应式系统实现的,Vue2用Object.defineProperty劫持数据,Vue3用Proxy代理对象。
其次是组件化系统,可以将复杂界面拆分成独立的、可复用的组件。每个组件都有自己的模板、逻辑和样式,降低了代码的耦合度。
再就是声明式模板语法,使用双花括号插值、v-if、v-for等指令声明式地将数据渲染到DOM,比原生的DOM操作更直观。
Vue还使用虚拟DOM来提升性能,通过diff算法计算出最小的DOM操作,避免频繁的真实DOM更新。整体上Vue遵循MVVM架构模式,学习曲线相对平缓,既保持了灵活性又不会让初学者感到困惑。
面试官真正想听什么
不是让你背官网定义,而是想知道你理解不理解Vue解决了什么问题。
很多人张口就来"MVVM、虚拟DOM、指令系统",听起来在背书。面试官期待听到的是:你用Vue做过什么、为什么选Vue、Vue哪点打动了你。
加分回答
"Vue最打动我的是渐进式设计。我第一个项目只是在表单页用Vue做数据绑定和验证,后来需求复杂了,逐步引入Router和Vuex。不像有些框架要么全用要么不用,Vue让我根据项目规模灵活选择。
响应式系统 特别实用,改数据视图自动刷新,做购物车、表单这种频繁交互的页面省很多事。再配合组件化,用户信息卡片、商品列表项这些重复的UI封装成组件,复用起来很方便。"
减分回答
❌ "Vue.js是一个基于MVVM架构的渐进式JavaScript框架..."(纯背概念)
❌ "Vue比React简单好学"(对比其他框架容易踩坑)
❌ 只说概念不说实际用途(暴露没做过项目)
2. Vue的生命周期钩子有哪些?每个阶段都做了什么?
速记公式:创建挂载更新销毁
- created: 调API、初始化数据
- mounted: 操作DOM、初始化插件
- updated: 响应数据变化
- destroyed/unmounted: 清理定时器、解绑事件
标准答案
Vue2和Vue3的生命周期钩子基本一致,Vue2有8个核心钩子,Vue3主要是改了命名。
创建阶段 有beforeCreate和created。beforeCreate时实例刚创建,data和methods还没初始化;created时完成了数据观测和方法绑定,但DOM还没生成。这个阶段通常用来初始化数据、调用API获取数据,因为这时候响应式数据已经准备好了。
挂载阶段 有beforeMount和mounted。beforeMount时开始模板编译;mounted时DOM已经挂载完成,可以访问到真实的DOM元素了。这个阶段适合操作DOM、初始化第三方库(比如Echarts、Swiper),或者需要获取元素尺寸的操作。
更新阶段有beforeUpdate和updated。当响应式数据变化时,beforeUpdate在DOM更新前触发,updated在DOM更新后触发。需要注意的是,updated里要避免修改数据,否则会造成无限循环更新。
销毁阶段 在Vue2是beforeDestroy和destroyed,Vue3改名为beforeUnmount和unmounted,语义更清晰。beforeDestroy/beforeUnmount用来做清理工作,比如清除定时器、解绑事件监听、取消网络请求等,防止内存泄漏。
Vue3的Composition API中,setup函数相当于beforeCreate和created的结合,其他钩子需要加on前缀使用,如onMounted、onUpdated等。

面试官真正想听什么
生命周期是判断你有没有真做过项目的关键。
会背8个钩子名的人一抓一大把,但面试官真正想知道的是:你在项目里到底在哪个钩子做了什么事。
加分回答
"我做电商后台时,在created里调用获取商品列表的API,因为这时候data已经初始化了,可以把接口数据赋值给响应式变量,而且比mounted早执行,能更快拿到数据。
在mounted里初始化Echarts图表,因为需要拿到DOM元素才能渲染图表。最开始我在created里初始化,结果报错找不到DOM,后来才知道mounted才是DOM挂载完成的时机。
在beforeDestroy(Vue3是beforeUnmount)里清理定时器。我做过一个实时数据刷新的需求,用setInterval定时请求接口,如果不在销毁前clearInterval,切换路由后定时器还在跑,造成内存泄漏。这个坑我踩过,后来养成习惯,有定时器、事件监听的地方一定记得清理。"
减分回答
❌ 只背名字不说用途:"beforeCreate、created、beforeMount..."(机械记忆)
❌ "created和mounted都差不多"(说明没踩过坑)
❌ 说不出具体在哪个钩子做过什么(暴露项目经验水分大)
常见追问
Q: created和mounted的区别?
A: created时数据初始化完成但DOM还没生成,mounted时DOM已挂载。所以调接口用created(更早拿到数据),操作DOM用mounted(确保元素存在)。
Q: 为什么要在beforeDestroy清理?
A: 防止内存泄漏。定时器、事件监听这些如果不清理,组件销毁了但它们还在运行,会占用内存。我之前就因为没清理定时器,页面切来切去后浏览器越来越卡。
3. Vue中v-if和v-show的区别?各自的使用场景?
速记公式:if真删假建,show常驻切显
- v-if: 条件为false时直接从DOM移除,true时重新创建
- v-show: 始终在DOM里,只是用display:none隐藏
标准答案
v-if和v-show的核心区别在于元素处理方式:
v-if是真正的条件渲染,通过动态创建和销毁DOM元素来控制显示。当条件为false时,对应的元素及其子组件会被完全从DOM中移除,组件的生命周期钩子也会执行;当条件变为true时,元素重新创建并插入DOM。这意味着v-if有更高的切换开销,但初始渲染时如果条件为false,可以避免不必要的渲染。
v-show则始终保持元素在DOM中,只是通过切换CSS的display属性来控制显隐。切换开销很小,但初始渲染时会创建所有元素。
使用场景选择:
频繁切换显示状态的场景用v-show,比如标签页切换、下拉菜单的展开收起、模态框的显示隐藏。这些场景切换频率高,用v-show避免反复创建销毁DOM的性能开销。
运行时很少改变条件的场景用v-if,比如用户权限控制、不同用户角色显示不同功能模块、首次加载后基本不变的内容。这些场景如果条件不满足,用v-if可以完全不渲染,节省初始渲染开销。
另外,v-if支持在template标签上使用来包装多个元素,而v-show不支持。
面试官真正想听什么
这题看你懂不懂DOM操作的性能开销,能不能根据业务场景选合适方案。
很多人只会说"v-if销毁DOM,v-show切换display",但说不出什么时候该用哪个,这就是理论派和实战派的区别。
加分回答
"我做后台管理系统的Tab切换时踩过坑。一开始用v-if切换'商品管理'和'订单管理',结果用户频繁切Tab时,组件反复创建销毁,每次都要重新请求数据、重新渲染表格,体验很差。
后来改成v-show,组件保留在DOM里,切换只改display。但又有新问题:所有Tab的数据在页面加载时都初始化了,首屏变慢。
最终方案是组合使用:
Tab切换本身用v-show,避免反复创建销毁;Tab里的大型表格组件用v-if加懒加载,首屏不加载所有Tab的数据。
选择标准就一句话:切换频率高用v-show,初次渲染成本高用v-if。"
减分回答
❌ "v-if性能不如v-show"(太绝对,初次渲染v-if更优)
❌ 只说原理不说场景(理论派)
❌ "看心情用"(随意派,暴露没想过性能问题)
实战技巧
什么时候必须用v-if:
- 权限控制(没权限的模块根本不创建)
- 条件很少改变(登录前后的界面切换)
- 需要配合template包装多个元素
什么时候必须用v-show:
- 弹窗、下拉菜单(频繁开关)
- Tab页切换
- 折叠面板
4. Vue中v-for指令如何使用?为什么需要绑定key属性?
速记公式:循环加key,唯一稳定
- v-for遍历: 数组、对象、数字都能遍历
- key作用: 帮Vue识别节点身份,优化DOM复用
标准答案
v-for的基本使用:
v-for指令用于循环渲染列表数据,支持遍历数组、对象和数字。基本语法是v-for="item in list"
,可以获取索引v-for="(item, index) in list"
,遍历对象时可以获取键名v-for="(value, key) in object"
,还能遍历数字v-for="n in 10"
。
key属性的作用:
key是Vue虚拟DOM diff算法的重要标识,它告诉Vue每个节点的唯一身份。当列表数据发生变化时,Vue会通过key来判断哪些节点可以复用,哪些需要重新创建或销毁。
如果不绑定key或使用index作为key,在列表项顺序改变时会导致组件状态错乱 和性能问题。比如在用户管理界面中,如果列表项包含输入框,没有正确的key会导致删除用户后,剩余用户的输入内容出现在错误的位置。
正确做法是使用数据的唯一标识作为key ,如用户ID、商品ID等。这样Vue就能准确追踪每个列表项的变化,确保组件状态正确维护,同时优化渲染性能。记住key必须是稳定、唯一的标识符,避免使用随机值或数组索引。

面试官真正想听什么
key是判断你理不理解虚拟DOM diff算法的试金石。
90%的人只知道"要加key",但说不清楚为什么,说不出不加key会出什么问题。这题答好了,面试官会觉得你对Vue底层有理解。
加分回答
"之前做用户列表管理时踩过坑。用户列表每一项有个输入框,我最开始没加key,删除第一个用户后,发现第二个用户的输入框内容跑到第一个位置了。
**原因是Vue复用了DOM节点。**没有key时,Vue按顺序对比,发现'有3个li变成2个li',就复用前两个li,删掉最后一个。但输入框的值是DOM自己维护的,Vue不知道,所以出现了错位。
后来我用index做key,想着'总比不加强'。结果删除中间某一项时,还是会出问题,因为删除后index重新排列,Vue还是会错误地复用节点。
最终用用户ID做key,每个用户有唯一标识,Vue就能精确判断'ID为123的用户被删了,ID为456的用户还在',不会乱复用DOM。
这个坑让我明白:key不是Vue的形式要求,而是diff算法的必需品。key越唯一稳定,Vue的更新就越精准。"
减分回答
❌ "加key是为了提升性能"(不准确,主要是为了正确追踪节点)
❌ "用index做key没问题"(暴露不懂diff算法)
❌ 说不出不加key会出什么具体问题(理论派)
常见追问
Q: 为什么不能用index做key?
A: index会随着数组变化而变化。比如删除第一项,原来index为1的元素变成index为0,Vue会认为是同一个元素,导致错误复用。只有在列表只做追加、从不删除或重排时,index才勉强可以用。
Q: 用随机数做key行吗?
A: 不行。每次渲染生成新的随机数,Vue会认为所有节点都是新的,全部重新创建,完全失去了diff优化的意义。
5. Vue模板语法中插值表达式{{}}、v-text、v-html的区别?
速记公式:插转文,text全替,html慎用
- 插值{{}}: 转义文本,可混合内容
- v-text: 转义文本,替换全部内容
- v-html: 解析HTML,有XSS风险
标准答案
Vue模板中的插值表达式{{}}
、v-text
和v-html
都用于数据绑定,但它们的渲染机制和安全性存在显著差异。
插值表达式{{}}
:
会将内容作为纯文本插入到DOM节点中,支持JavaScript表达式计算,在编译时会被转换为文本节点。当数据包含HTML标签时,标签会被转义显示而不会被解析。比如{{ '<span>hello</span>' }}
会在页面上直接显示<span>hello</span>
这个字符串。插值表达式可以与其他文本混合使用,比如<div>用户名:{{ username }}</div>
。
v-text指令:
功能与插值表达式基本相同,也是将数据作为纯文本渲染,HTML标签同样会被转义。不同之处在于v-text会替换元素的整个文本内容,而插值表达式可以与其他文本混合。使用v-text可以避免页面加载时出现未编译的{{}}
闪烁问题(FOUC)。
v-html指令:
会将数据作为HTML片段解析并插入DOM,HTML标签会被正确渲染。比如v-html="'<span>hello</span>'"
会渲染出一个span元素。但这种方式存在XSS攻击风险,不应该用于渲染用户输入的内容。
使用建议:
显示用户名、文章标题等普通文本时使用插值表达式或v-text;需要渲染富文本编辑器内容或后端返回的HTML片段时才使用v-html,并确保内容已经过安全处理。
面试官真正想听什么
这题考察你对安全性的认知和实际应用场景的判断。
很多人只知道三者的渲染区别,但不知道为什么要有三种方式,更不知道v-html的安全风险。面试官想看你有没有安全意识。
加分回答
"我在做内容管理系统时,遇到过这三种情况:
显示用户评论 用插值表达式{{ comment }}
,因为用户输入不可信,必须转义。之前有人试图在评论里写<script>alert('XSS')</script>
,插值表达式自动把标签转义成文本显示出来,没有执行恶意代码。
显示富文本文章内容 用v-html
,因为文章确实需要渲染HTML标签来保持格式。但我们在后端做了白名单过滤,只允许p、span、strong这些安全标签,script、iframe这些危险标签会被过滤掉。
v-text主要用在性能敏感的地方,比如大量列表渲染时,用v-text避免插值表达式的闪烁问题,虽然现在构建工具都会预编译,这个问题不太明显了。
核心原则就是:不信任的内容绝不用v-html,必须用v-html的地方一定要做XSS防护。"
减分回答
❌ "v-html就是渲染HTML的"(不提安全风险)
❌ "三个随便用哪个都行"(没有安全意识)
❌ 说不出实际应用场景(理论派)
实战技巧
XSS防护方案:
- 后端对用户输入做HTML实体转义
- 使用DOMPurify等库做前端二次过滤
- 设置CSP(Content Security Policy)策略
- 富文本编辑器配置白名单,只允许安全标签
6. Vue中事件处理v-on指令如何使用?事件修饰符有哪些?
速记公式:on监听,stop阻冒泡,prevent阻默认,链式调用
常用修饰符:.stop .prevent .capture .self .once
标准答案
v-on的基本使用:
Vue中的v-on
指令用于监听DOM事件并执行相应的JavaScript代码。可以使用v-on:click
或简写@click
来绑定点击事件。事件处理函数可以直接写在模板中,也可以绑定到methods中定义的方法。例如@click="handleClick"
或@click="count++"
。
常用事件修饰符:
.stop
用于阻止事件冒泡,相当于调用event.stopPropagation()
。在嵌套元素中,当你只想触发当前元素的事件,不想触发父元素的事件时使用。
.prevent
阻止默认行为,相当于event.preventDefault()
。比如阻止表单提交、阻止a标签跳转等。
.capture
使用事件捕获模式,事件从外层元素开始触发。
.self
只在事件目标是当前元素本身时触发,不会因为子元素冒泡而触发。
.once
只触发一次事件,触发后自动移除监听器。
按键修饰符:
.enter
、.tab
、.delete
、.esc
、.space
等,用于监听键盘特定按键。比如@keyup.enter="submit"
监听回车键。
鼠标修饰符:
.left
、.right
、.middle
分别对应鼠标左中右键。
修饰符链式调用:
修饰符可以串联使用,比如@click.stop.prevent="doThis"
同时阻止冒泡和默认行为。需要注意链式调用的顺序,因为顺序会影响执行结果。
面试官真正想听什么
这题看你对事件机制的理解和实际开发经验。
会说修饰符名字的人很多,但面试官想知道你在什么场景下用过这些修饰符,有没有踩过事件冒泡的坑。
加分回答
"我在做模态框组件时,遇到过事件冒泡的坑。点击模态框内部不应该关闭弹窗,但我在遮罩层绑定了@click="closeModal"
,结果点击内容区域也会触发关闭,因为事件冒泡到遮罩层了。
后来在内容区域加了@click.stop
,阻止冒泡,问题解决。这让我养成习惯,凡是嵌套元素都要考虑冒泡问题。
表单提交最常用.prevent
,比如@submit.prevent="handleSubmit"
,避免表单提交后页面刷新,让我们用Ajax异步提交。
.once在性能优化时很有用 。比如引导蒙层只需要显示一次,用@click.once="hideGuide"
,点击后自动解绑,不需要手动removeEventListener。
修饰符可以链式调用这点很重要,@click.stop.prevent
比在methods里写两行代码简洁多了。但要注意顺序,@click.prevent.self
和@click.self.prevent
效果不一样,前者先阻止默认行为再判断self,后者先判断self再阻止。"
减分回答
❌ 只背修饰符名字不说用途(机械记忆)
❌ "stop和prevent差不多"(概念混淆)
❌ 说不出实际应用场景(理论派)
常见追问
Q: .stop和.self有什么区别?
A: .stop阻止事件继续冒泡,子元素的事件不会传到父元素;.self只有点击元素自身时才触发,点击子元素冒泡上来不会触发。使用场景不同,.stop用于完全隔断冒泡,.self用于区分自身和子元素的点击。
Q: 修饰符可以组合使用吗?有顺序要求吗?
A: 可以链式调用,顺序会影响执行结果。比如.prevent.self
会阻止所有点击的默认行为,然后只在点击自身时执行处理函数;.self.prevent
则只有在点击自身时才阻止默认行为。
7. Vue双向数据绑定v-model的实现原理?如何在自定义组件中使用?
速记公式:属性事件语法糖,数据流动更直观
原生元素: 绑定value属性+监听input事件
自定义组件: Vue2用value/input,Vue3用modelValue/update:modelValue
标准答案
v-model的本质:
Vue的v-model
本质上是语法糖,它将数据绑定和事件监听结合在一起。在原生表单元素上,v-model
会根据元素类型自动选择正确的属性和事件进行绑定。比如input
元素绑定value
属性和input
事件,checkbox
绑定checked
属性和change
事件,select
绑定value
属性和change
事件。
底层实现机制:
通过Object.defineProperty
(Vue2)或Proxy
(Vue3)劫持数据属性的getter
和setter
。当数据变化时触发视图更新,当用户输入时通过事件监听更新数据,形成双向绑定。
比如<input v-model="message">
实际等价于:
html
<input :value="message" @input="message = $event.target.value">
在自定义组件中使用:
Vue2中,子组件需要接收名为value
的prop
,并在数据变化时emit
名为input
的事件:
javascript
// 子组件
props: ['value'],
methods: {
handleChange(val) {
this.$emit('input', val)
}
}
父组件就能直接用v-model
:
html
<CustomInput v-model="userInput" />
Vue3中默认是modelValue
prop
和update:modelValue
事件。使用defineModel
可以更简洁:
javascript
const model = defineModel()
// 在模板中直接 <input v-model="model" />
你也可以通过model
选项(Vue2)自定义prop名称和事件名称,实现多个v-model绑定。

面试官真正想听什么
这题考察你对双向绑定原理的理解和封装组件的能力。
很多人只知道"v-model是语法糖",但说不清楚糖的背后是什么,更不会在自己的组件里实现v-model。这是判断你会不会封装可复用组件的关键。
加分回答
"我在封装搜索组件时用过自定义v-model。最开始我让父组件传searchText,子组件通过$emit('update-search', newValue)通知父组件,父组件再@update-search更新数据,写起来很繁琐。
后来了解到v-model的原理,在子组件里定义:
javascript
props: ['value'],
methods: {
handleInput(e) {
this.$emit('input', e.target.value)
}
}
父组件就能直接<SearchBox v-model="keyword" />
,代码简洁多了。
Vue3的defineModel更简洁:
javascript
// 子组件
const model = defineModel()
// 模板直接用 <input v-model="model" />
这样父组件用<SearchBox v-model="keyword" />
就能实现双向绑定,代码量少了一半。
理解v-model的本质后,我现在封装表单组件都会实现v-model接口,让组件用起来更符合Vue的习惯。"
减分回答
❌ "v-model就是双向绑定"(说法不准确,是语法糖)
❌ 说不清楚v-model等价于什么代码(不理解原理)
❌ 不知道怎么在自定义组件中实现(只会用不会封装)
常见追问
Q: v-model可以用在多个属性上吗?
A: Vue2只能有一个v-model,但可以通过.sync修饰符实现多个双向绑定。Vue3支持多个v-model,用v-model:propName
语法,比如v-model:title
和v-model:content
。
Q: v-model和.sync的区别?
A: 本质都是语法糖。v-model默认绑定value/input,.sync可以自定义属性名。Vue3统一了语法,都用v-model:propName,废弃了.sync。
8. Vue中computed和watch的区别?使用场景?
速记公式:computed计算缓存有返回,watch监听异步无返回
- computed: 计算属性,有缓存,必须返回值
- watch: 侦听器,监听变化,执行副作用
标准答案
computed和watch都是Vue的响应式特性,但它们解决的问题不同。
computed计算属性:
专注于数据计算和缓存,是声明式的依赖追踪。Vue会自动收集computed内部访问的响应式数据作为依赖,当依赖变化时重新计算并缓存结果。多次访问同一个computed属性只会执行一次计算,直到依赖再次变化。computed必须有返回值,不应该有副作用(不要在computed里修改数据或调用API)。
适用于基于现有数据派生新数据的场景,比如购物车总价计算、用户全名拼接、列表筛选等。computed更像是Excel中的公式,当基础数据变了,公式结果自动更新并缓存起来。
watch侦听器:
专注于数据监听和副作用处理,是命令式的数据监听。需要明确指定要监听的数据源,当数据变化时执行回调函数。每次变化都会触发执行且不提供缓存机制。watch不需要返回值,主要用于执行异步操作或复杂业务逻辑。
适用于数据变化后需要执行异步操作或开销较大操作的场景,比如监听搜索关键词变化后重新请求列表、监听路由变化发送埋点、监听用户状态变化更新本地存储等。watch更像是事件监听器,当某个数据变化时触发特定操作。
核心区别:
- computed有缓存,watch无缓存
- computed必须同步返回值,watch适合异步操作
- computed是多对一(多个依赖计算一个结果),watch是一对多(监听一个数据执行多个操作)
面试官真正想听什么
这题是判断你会不会合理选择Vue API的经典题。
很多人背得出区别,但在实际项目中该用computed的地方用watch,该用watch的地方用computed,暴露对响应式系统理解不深。
加分回答
"我刚开始学Vue时分不清这两个。做购物车功能时,想计算总价,我用watch监听商品列表:
javascript
watch: {
cartItems: {
handler() {
this.totalPrice = this.cartItems.reduce(...)
},
deep: true
}
}
后来发现每次访问totalPrice都要手动触发计算,而且要深度监听整个数组,性能不好。改成computed后:
javascript
computed: {
totalPrice() {
return this.cartItems.reduce((sum, item) => sum + item.price * item.count, 0)
}
}
代码简洁了,而且自动缓存,访问多次只计算一次。
watch我主要用在搜索场景。 监听搜索关键词变化后防抖请求接口:
javascript
watch: {
keyword(newVal) {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.fetchSearchResults(newVal)
}, 300)
}
}
这种需要异步操作的场景,computed做不了,必须用watch。
判断标准: 需要计算得出新值用computed,需要响应变化执行操作用watch。"
减分回答
❌ "computed性能比watch好"(太绝对,不同场景不同选择)
❌ "都差不多"(完全不理解)
❌ 说不出具体使用场景(理论派)
常见追问
Q: computed能调接口吗?
A: 不建议。computed应该是纯函数,只做计算。调接口是异步操作,应该用watch或methods。而且computed会在依赖变化时频繁执行,调接口会造成大量无用请求。
Q: watch能监听computed吗?
A: 可以。computed本质也是响应式属性,可以被watch监听。但这种场景比较少见,通常说明设计有问题。
9. Vue中methods、computed、watch三者的区别?
速记公式:方法主动,计算缓存,侦听副作用
methods: 每次调用都执行,主动调用
computed: 基于依赖缓存,自动触发
watch: 监听变化,执行副作用
标准答案
这三个概念在响应式处理和执行时机上有本质区别。
methods普通方法:
是普通方法集合,每次调用都会重新执行,不具备缓存机制。当你需要处理用户交互、提交表单、调用API等主动触发的操作时使用methods。比如handleClick
、submitForm
这类事件处理函数。methods是完全受控的,只有你显式调用时才执行。
computed计算属性:
是计算属性,基于响应式依赖进行缓存,只有当依赖的数据发生变化时才会重新计算,否则返回缓存结果。它适合处理需要根据现有数据计算得出新值的场景,典型应用是购物车总价计算、用户全名拼接、列表过滤等。computed必须有返回值,且不应该有副作用(不要修改数据、不要调用API)。在模板中多次使用computed只会计算一次,而methods会执行多次。
watch侦听器:
是侦听器,专门监听特定数据的变化并执行相应的回调函数。它不需要返回值,主要用于执行异步操作或开销较大的操作,比如监听路由变化发送请求、监听输入框内容进行搜索防抖、监听用户状态变化更新本地存储等。watch是响应式的,当监听的数据变化时自动执行。
三者对比:
对比项 | methods(方法) | computed(计算属性) | watch(侦听器) |
---|---|---|---|
执行时机 | 需要主动调用 | 依赖变化时自动执行 | 监听的数据变化时自动执行 |
缓存机制 | 无缓存,每次都执行 | 有缓存,依赖不变返回缓存 | 无缓存,每次变化都执行 |
返回值 | 可有可无 | 必须有返回值 | 不需要返回值 |
使用场景 | 事件处理、主动操作 | 数据计算、派生新值 | 响应数据变化执行副作用(如异步操作) |
面试官真正想听什么
这题是综合考察你对Vue响应式系统的整体理解。
能说清楚三者区别的人不少,但面试官更想知道:你在实际项目中怎么选择,有没有用错过,为什么会用错。
加分回答
"我之前做过一个错误示范。在模板里显示格式化后的价格,我用methods:
html
<div>{{ formatPrice(item.price) }}</div>
结果发现页面很卡,因为每次组件更新,formatPrice都会重新执行,哪怕price根本没变。后来改成computed:
javascript
computed: {
formattedPrice() {
return '¥' + this.item.price.toFixed(2)
}
}
性能问题解决了,因为只有price变化时才重新计算。
**methods我主要用在事件处理:**点击按钮提交表单、删除某一项这种需要主动触发的操作。
**computed用在数据派生:**根据筛选条件过滤列表、计算购物车总价、拼接用户信息等纯计算场景。
**watch用在副作用操作:**搜索框输入防抖请求接口、监听语言切换更新国际化文本、用户信息变化同步到localStorage。
选择原则就是:主动调用用methods,数据计算用computed,响应变化执行操作用watch。"
减分回答
❌ "都能实现功能,差不多"(完全不理解设计意图)
❌ "computed性能最好"(不准确,场景不同)
❌ 说不出实际项目中用错过的例子(缺少反思)
常见追问
Q: 什么时候computed和methods可以互换?
A: 如果计算逻辑不依赖响应式数据,或者只需要执行一次,可以用methods。但在模板中频繁调用、且依赖响应式数据的场景,必须用computed利用缓存。
Q: watch可以替代computed吗?
A: 技术上可以,但代码会很啰嗦。比如计算全名,用watch要监听firstName和lastName,分别更新fullName;用computed只需要computed: { fullName() { return this.firstName + this.lastName } }
,简洁多了。
10. Vue模板编译过程是怎样的?template如何转换成渲染函数?
速记公式:解析AST,优化标记,生成代码
三个阶段:模板解析 → AST优化 → 代码生成
标准答案
Vue模板编译是将template语法转换为可执行JavaScript渲染函数的过程。整个编译过程分为三个核心阶段:
第一阶段:模板解析(Parse)
编译器会逐字符扫描模板字符串,进行词法分析和语法分析。词法分析识别出标签、属性、插值表达式、指令等token。比如遇到{{
时知道这是插值的开始,遇到v-
时识别为指令。语法分析将这些token组织成AST抽象语法树,每个DOM节点、文本节点、表达式都会成为AST中的节点,形成完整的树形结构。
第二阶段:AST优化(Optimize)
Vue会遍历AST,标记静态节点和静态根节点。静态节点是指内容永远不会改变的节点,比如纯文本或没有任何动态绑定的元素。标记静态节点的目的是在后续的patch过程中可以跳过这些节点的diff比对,直接复用,提升性能。
第三阶段:代码生成(Generate)
将优化后的AST转换为渲染函数代码字符串。插值表达式{{ message }}
会变成_s(message)
,v-if
指令转换为三元表达式,v-for
转换为_l
函数调用。最终生成的渲染函数类似:
javascript
function render() {
return _c('div', [_v(_s(message))])
}
这个render函数在组件渲染时被调用,返回虚拟DOM(VNode),Vue再通过patch函数将虚拟DOM渲染成真实DOM。
编译时机:
整个编译过程可以在构建时完成(使用vue-loader),也可以在运行时进行(使用完整版Vue)。生产环境推荐构建时编译,可以使用更小的运行时版本,提升性能。

面试官真正想听什么
这题考察你对Vue底层原理的理解深度。
模板编译是Vue架构中的重要环节,能答好这题说明你不只是会用Vue,还理解Vue是怎么工作的。面试官想看你对编译原理有没有基本认知。
加分回答
"我最开始不理解为什么Vue既支持template又支持render函数。后来了解编译过程才明白:template最终也是转成render函数的。
template写起来直观,但需要编译;render函数直接写VNode创建逻辑,跳过编译直接执行。
在工程化项目中,我们用vue-loader在构建时编译template。 这样运行时不需要包含编译器代码,能减少30%的包体积。单文件组件的template在webpack打包时就被编译成render函数了。
AST优化这一步很关键。 Vue会标记静态节点,比如<div>静态文本</div>
这种永远不变的内容,后续diff时直接跳过,节省很多性能开销。这也是为什么Vue鼓励我们多用静态内容,少用动态绑定。
理解编译过程后,我在写组件时会更注意:
- 复杂逻辑用computed提前计算,减少模板中的表达式
- 大量静态内容拆成独立组件,利用静态标记优化
- 动态性很强的场景直接写render函数,跳过编译开销"
减分回答
❌ "模板会转成虚拟DOM"(不准确,是转成render函数,render函数返回VNode)
❌ 说不出编译的三个阶段(只知道表面)
❌ 不知道构建时编译和运行时编译的区别(没有工程化经验)
常见追问
Q: 为什么要有AST这个中间产物?
A: AST是模板和渲染函数之间的桥梁。有了AST,可以对模板做静态分析和优化(标记静态节点),还可以做代码转换(比如JSX转template)。如果直接从模板字符串生成代码,很难做这些优化。
Q: 运行时编译和构建时编译的区别?
A: 运行时编译是在浏览器里执行编译,需要完整版Vue(包含编译器),包体积大;构建时编译是在webpack打包时完成,运行时只需要Vue运行时版本(不含编译器),包体积小30%,而且编译过程不占用浏览器性能。生产环境一定用构建时编译。
总结
这10道Vue基础题,是面试的第一关。答好这些题,面试官会给你打上"基础扎实"的标签;答不好,后面的项目经验再牛也白搭。
每道题的核心不是背答案,而是理解:
- 为什么Vue要这样设计(设计理念)
- 你在项目中怎么用的(实战经验)
- 踩过什么坑、怎么解决的(问题解决能力)
接下来该做什么:
- 把这10题的标准答案背下来,面试时能流畅表达
- 回想自己的项目,给每个知识点找一个实际案例
- 动手验证,把不确定的点在代码里跑一遍
下一篇我会讲Vue组件系统的12道题 :组件定义、通信方式、slot插槽、动态组件...这些是面试官判断你"会不会写组件化代码"的关键。 80%的人挂在组件通信这一关,因为他们说不清楚项目里是怎么做组件设计的。
最近好多同学挂在 HR 面而不知道为什么,这些问题你都会吗:
- 你对薪资有什么期望?
- 如果工作中遇到你不会的问题,你会怎么解决呢?
- 用三个词形容一下你自己,并说说为什么选择这三个词?
- 如果需要你在很短时间内掌握一项新技能,你会怎么做?
没有答题思路? 快来牛面题库看看吧,这是我们打造的面试学习一站式平台,拥有丰富的免费题库资源,AI模拟面试等等功能,加入我们,早日斩获Offer吧。
留言区互动:
这10题里,你觉得最难的是哪一道?或者你在面试中被问到过但答得不好的是哪题?
在评论区告诉我,点赞最高的问题,我会单独写一篇深度解析。