Vue基础10题:答错一道,别说你熟悉Vue

前言

上周面了个应届生,简历上写着"熟悉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-textv-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)劫持数据属性的gettersetter。当数据变化时触发视图更新,当用户输入时通过事件监听更新数据,形成双向绑定。

比如<input v-model="message">实际等价于:

html 复制代码
<input :value="message" @input="message = $event.target.value">

在自定义组件中使用:

Vue2中,子组件需要接收名为valueprop,并在数据变化时emit名为input的事件:

javascript 复制代码
// 子组件
props: ['value'],
methods: {
  handleChange(val) {
    this.$emit('input', val)
  }
}

父组件就能直接用v-model

html 复制代码
<CustomInput v-model="userInput" />

Vue3中默认是modelValue propupdate: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:titlev-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。比如handleClicksubmitForm这类事件处理函数。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要这样设计(设计理念)
  • 你在项目中怎么用的(实战经验)
  • 踩过什么坑、怎么解决的(问题解决能力)

接下来该做什么:

  1. 把这10题的标准答案背下来,面试时能流畅表达
  2. 回想自己的项目,给每个知识点找一个实际案例
  3. 动手验证,把不确定的点在代码里跑一遍

下一篇我会讲Vue组件系统的12道题 :组件定义、通信方式、slot插槽、动态组件...这些是面试官判断你"会不会写组件化代码"的关键。 80%的人挂在组件通信这一关,因为他们说不清楚项目里是怎么做组件设计的。

最近好多同学挂在 HR 面而不知道为什么,这些问题你都会吗:

  1. 你对薪资有什么期望?
  2. 如果工作中遇到你不会的问题,你会怎么解决呢?
  3. 用三个词形容一下你自己,并说说为什么选择这三个词?
  4. 如果需要你在很短时间内掌握一项新技能,你会怎么做?

没有答题思路? 快来牛面题库看看吧,这是我们打造的面试学习一站式平台,拥有丰富的免费题库资源,AI模拟面试等等功能,加入我们,早日斩获Offer吧。


留言区互动:

这10题里,你觉得最难的是哪一道?或者你在面试中被问到过但答得不好的是哪题?

在评论区告诉我,点赞最高的问题,我会单独写一篇深度解析。

相关推荐
有梦想的攻城狮4 小时前
从0开始学vue:npm命令详解
前端·vue.js·npm
我是日安5 小时前
从零到一打造 Vue3 响应式系统 Day 23 - Watch:基础实现
前端·javascript·vue.js
rggrgerj10 小时前
VUE3+element plus 实现表格行合并
javascript·vue.js·elementui
huangql52010 小时前
UniApp + Vite + Vue3 + TypeScript 项目中 ESLint 与 Prettier 的完整配置指南
vue.js·typescript·团队开发·代码规范
fxshy10 小时前
Vue3和element plus在el-table中使用el-tree-select遇到的change事件坑
javascript·vue.js·elementui
北慕阳10 小时前
自存19-48
javascript·vue.js·elementui
洛可可白1 天前
把 Vue2 项目“黑盒”嵌进 Vue3:qiankun 微前端实战笔记
前端·vue.js·笔记