前端Vue面试八股常考题(一)
文章目录
- 1、什么是 Vue 指令?Vue 有哪些常用的指令?
- 常用指令分类及说明:
- 扩展:自定义指令
- 2、Vue 计算属性 computed 的函数名和 data 中的属性可以同名吗?为什么?
- 扩展:Vue 实例属性优先级
- 3、Vue 中 data 的属性可以与 methods 中的方法同名吗?为什么?
- 示例:冲突场景
- 4、Vue 的 v-cloak 和 v-pre 指令有什么作用?
- 1. v-cloak 指令
- 2. v-pre 指令
- 示例:
- 5、Vue 的 v-show 和 v-if 有什么区别?使用场景分别是什么?
- 使用场景:
- 示例:
- 扩展:与生命周期的关系
- 6、在 Vue 组件中写 name 选项有什么作用?
- 1. 调试与开发体验
- 2. 递归组件引用
- 3. 动态组件与 keep-alive
- 4. 不同 API 中的定义方式
- 7、Vue 2 和 Vue 3 支持哪个版本以上的 IE 浏览器?
- 8、为什么不建议在 Vue 中同时使用 v-if 和 v-for?
- 1. 优先级问题导致的行为差异
- 2. 正确替代方案
- 9、在 Vue 渲染模板时,如何保留模板中的 HTML 注释?
- 10、为什么 Vue 中的 data 属性是一个函数而不是一个对象?
- 1. 核心原因:避免组件实例间数据共享
- 2. 根实例 vs 组件实例的区别
- 3. Vue 2 与 Vue 3 的实现差异
- 11、Vue 的 template 标签有什么用?
- 1. 核心用途
- 2. Vue 2 vs Vue 3 的差异
- 12、Vue 中 MVVM、MVC 和 MVP 模式的区别是什么?
- 扩展:Vue 中的 MVVM 实现
1、什么是 Vue 指令?Vue 有哪些常用的指令?
Vue 指令是带有 v-
前缀的特殊属性,其职责是当表达式的值改变时,将变化高效应用到 DOM 上。
常用指令分类及说明:
-
属性绑定指令
-
v-bind:动态绑定属性或组件 prop,简写为
<img :src="imageSrc"> <button :[key]="value">动态属性名</button>
-
v-model:在表单元素上创建双向数据绑定
<input v-model="message"> <!-- 等价于 --> <input :value="message" @input="message = $event.target.value">
-
-
事件绑定指令
-
v-on:绑定事件监听器,简写为@
<button @click="doThis">点击事件</button> <button @[event]="doThis">动态事件名</button>
-
-
条件渲染指令
-
v-if/v-else/v-else-if:根据条件动态创建或销毁 DOM 元素
<div v-if="type === 'A'">A</div> <div v-else-if="type === 'B'">B</div> <div v-else>Not A/B</div>
-
v-show:通过切换
display
属性控制元素显示 / 隐藏,不销毁 DOM<div v-show="isVisible">Hello</div>
-
-
列表渲染指令
-
v-for:基于数组或对象渲染列表,需使用
key
优化性能<div v-for="item in items" :key="item.id">{{ item.text }} </div>
-
-
内容渲染指令
- v-text:更新元素文本内容
- v-html:更新元素 innerHTML(注意 XSS 风险)
-
特殊功能指令
- v-slot:具名插槽或接收 prop 的插槽,简写为
#
- v-pre:跳过元素及其子元素的编译过程
- v-cloak:隐藏未编译模板直到实例准备完毕(需配合 CSS
[v-cloak] { display: none; }
) - v-once:只渲染一次,后续更新跳过
- v-slot:具名插槽或接收 prop 的插槽,简写为
扩展:自定义指令
Vue 允许注册自定义指令,钩子函数与组件生命周期类似:
// 全局注册
app.directive('focus', {mounted(el) { el.focus() }
})// 局部注册
export default {directives: {focus: {mounted(el) { el.focus() }}}
}
2、Vue 计算属性 computed 的函数名和 data 中的属性可以同名吗?为什么?
不可以同名,原因如下:
- 命名冲突本质:data 和 computed 最终都会作为 Vue 实例属性存在,若同名会导致实例属性被覆盖。
- 优先级顺序:data 优先级高于 computed,若同名,模板中会优先使用 data 数据,导致 computed 失效。
- 警告机制:Vue 初始化时会检测重复定义并抛出警告,避免不可预知的错误。
扩展:Vue 实例属性优先级
props > methods > data > computed > watch
后挂载的属性会覆盖先挂载的同名属性(如 methods 方法会覆盖 data 同名属性)。
3、Vue 中 data 的属性可以与 methods 中的方法同名吗?为什么?
不可以同名,因为:
- 实例属性共享命名空间:data、methods、computed 等会被合并到组件实例对象,同名会导致冲突。
- 方法覆盖属性:methods 优先级高于 data,同名时方法会覆盖 data 属性,导致数据无法访问。
示例:冲突场景
<script>
export default {data() { return { count: 10 } },methods: {count() { return this.count * 2 } // 错误!会覆盖 data.count}
}
</script>
4、Vue 的 v-cloak 和 v-pre 指令有什么作用?
1. v-cloak 指令
- 作用:隐藏未编译的模板内容,避免 “模板闪烁”(用户看到
{{ message }}
原始标签)。 - 使用方式:需配合 CSS 规则
[v-cloak] { display: none; }
,Vue 实例挂载后自动移除该属性。 - 应用场景:
- 无构建工具的开发环境(如直接在 HTML 中使用 Vue)。
- 大型应用加载时或网络较慢时提升用户体验。
2. v-pre 指令
- 作用:跳过元素及其子元素的编译过程,直接显示原始内容。
- 应用场景:
- 展示 Vue 模板语法(如文档示例)。
- 优化性能:对静态内容跳过编译。
- 保留 HTML 注释(默认编译会移除注释)。
示例:
<!-- v-cloak 示例 -->
<div v-cloak>{{ message }}</div><!-- v-pre 示例 -->
<span v-pre>{{ 这段内容不会被编译 }}</span>
5、Vue 的 v-show 和 v-if 有什么区别?使用场景分别是什么?
对比项 | v-if | v-show |
---|---|---|
渲染机制 | 条件为 false 时移除 DOM 元素 | 始终渲染,通过 display 控制显示 |
初始开销 | 惰性渲染(条件为 true 时才渲染) | 初始必渲染,开销更高 |
切换开销 | 销毁 / 重建 DOM,开销大 | 仅修改 CSS,开销小 |
分支支持 | 支持 v-else/v-else-if | 不支持分支 |
模板元素 | 可在 上使用 | 不可在 上使用 |
使用场景:
- v-if 适用场景:
- 条件不频繁切换(如用户权限控制)。
- 多条件分支(配合 v-else-if/v-else)。
- 需要完全销毁组件实例(如表单重置)。
- v-show 适用场景:
- 频繁切换显示状态(如标签页、对话框)。
- 需要结合 CSS 过渡动画(因元素始终存在于 DOM 中)。
示例:
<!-- v-if 示例:用户权限控制 -->
<admin-panel v-if="user.isAdmin"></admin-panel><!-- v-show 示例:频繁切换的对话框 -->
<div v-show="isDialogVisible" class="dialog">对话框内容</div>
扩展:与生命周期的关系
- v-if 为 false 时,组件不渲染,条件切换时触发完整生命周期。
- v-show 始终渲染组件,仅控制显示,生命周期仅触发一次。
6、在 Vue 组件中写 name 选项有什么作用?
Vue 组件的 name
选项用于显式声明组件名称,主要作用如下:
1. 调试与开发体验
- Vue DevTools 识别:设置
name
后,组件在 DevTools 中显示更直观,便于调试复杂应用。 - 错误堆栈信息:在报错时,
name
能明确显示问题发生的组件位置。
2. 递归组件引用
组件需通过 name
选项实现自引用:
<!-- 递归组件示例 -->
<script>
export default {name: 'TreeNode',props: {children: Array},template: `<ul><li v-for="child in children" :key="child.id">{{ child.name }}<TreeNode v-if="child.children" :children="child.children" /></li></ul>`
}
</script>
3. 动态组件与 keep-alive
- 动态组件切换:通过
name
缓存组件状态(如keep-alive
)。 - 异步组件加载:
name
可作为异步组件的标识。
4. 不同 API 中的定义方式
-
选项式 API:直接在组件选项中定义
name
。 -
组合式 API:通过
defineOptions
宏定义(Vue 3.3+):<script setup> defineOptions({name: 'MyComponent' }) </script>
7、Vue 2 和 Vue 3 支持哪个版本以上的 IE 浏览器?
版本 | 浏览器支持 | 原因 |
---|---|---|
Vue 2 | IE9+(含 IE9) | 使用 Object.defineProperty 实现响应式,IE8 及以下不支持该 API。 |
Vue 3 | 不支持任何版本 IE(包括 IE11) | 基于 ES6+ 语法和 Proxy 实现响应式,IE 无法兼容;官方推荐使用现代浏览器(Chrome、Firefox、Edge 等)。 |
8、为什么不建议在 Vue 中同时使用 v-if 和 v-for?
1. 优先级问题导致的行为差异
版本 | 优先级顺序 | 潜在问题 |
---|---|---|
Vue 2 | v-for > v-if | 先循环再条件判断,即使条件为 false 仍会遍历整个数组,性能浪费。 |
Vue 3 | v-if > v-for | 先条件判断再循环,但可能导致 v-if 无法访问 v-for 作用域内的变量(如 item ),引发编译错误。 |
2. 正确替代方案
-
场景 1:过滤列表项
使用计算属性或方法预先过滤数据:<script> export default {computed: {activeUsers() {return this.users.filter(user => user.isActive)}} } </script> <template><li v-for="user in activeUsers" :key="user.id">{{ user.name }}</li> </template>
-
场景 2:条件性渲染整个列表
使用<template>
分离逻辑:<template v-if="shouldRenderList"><li v-for="item in items" :key="item.id">{{ item.name }}</li> </template>
9、在 Vue 渲染模板时,如何保留模板中的 HTML 注释?
方法 | 适用版本 | 示例代码 | 特点 |
---|---|---|---|
comments 选项 | Vue 2 | new Vue({ comments: true }) | 全局配置,保留所有注释,可能增加打包体积。 |
v-pre 指令 | Vue 2/3 | <div v-pre><!-- 注释 --></div> | 跳过元素编译,保留内部所有内容(包括注释),但会导致该元素及其子元素无法使用 Vue 指令。 |
特殊注释语法 | Vue 3 | <!--[COMMENTS] 这是会被保留的注释 --> | 仅保留符合该格式的注释,其他注释仍会被移除,更精准控制。 |
10、为什么 Vue 中的 data 属性是一个函数而不是一个对象?
1. 核心原因:避免组件实例间数据共享
- 对象是引用类型:若
data
为对象,所有组件实例将共享同一数据对象,导致数据污染。 - 函数返回新对象:每个实例调用
data()
都会返回独立的数据副本,保证数据隔离。
2. 根实例 vs 组件实例的区别
场景 | 允许 data 为对象 | 原因 |
---|---|---|
根实例 | ✅ | 根实例仅创建一次,不存在复用问题,数据不会被共享。 |
组件实例 | ❌ | 组件可能被多次复用,若 data 为对象,所有实例将共享同一数据。 |
3. Vue 2 与 Vue 3 的实现差异
版本 | 响应式原理 | 数据独立性实现方式 |
---|---|---|
Vue 2 | Object.defineProperty | 通过 data() 返回对象后,对每个属性进行劫持,创建独立的 getter/setter。 |
Vue 3 | Proxy | 通过 data() 返回对象后,用 Proxy 代理整个对象,实现响应式,每个实例的 Proxy 独立。 |
11、Vue 的 template 标签有什么用?
<template>
标签在 Vue 中作为占位符或逻辑容器使用,其行为在 Vue 2 和 Vue 3 中有所不同:
1. 核心用途
-
条件渲染
:包裹多个元素,避免添加额外 DOM 节点:
<template v-if="condition"><h1>标题</h1><p>内容</p> </template>
-
列表渲染:与
v-for
结合,不生成额外 DOM:<template v-for="item in list" :key="item.id"><div>{{ item.name }}</div><span>{{ item.value }}</span> </template>
-
插槽定义:定义具名插槽或默认插槽:
<template #header><h1>头部内容</h1> </template>
2. Vue 2 vs Vue 3 的差异
版本 | 行为 | 示例 |
---|---|---|
Vue 2 | 始终作为占位符,编译后被移除,不影响最终 DOM。 | <template v-if="true"><div>内容</div></template> → 渲染为 <div>内容</div> 。 |
Vue 3 | 若未使用指令(如 v-if 、v-for ),会渲染为原生 <template> 标签;否则编译后移除。 | <template>原始内容</template> → 渲染为 <template>原始内容</template> (浏览器中不可见)。 |
12、Vue 中 MVVM、MVC 和 MVP 模式的区别是什么?
模式 | 核心结构 | 数据流方向 | Vue 中的应用场景 |
---|---|---|---|
MVVM | Model ←→ ViewModel ←→ View | 双向数据绑定 | Vue 框架的核心模式,通过 data 和 template 实现数据与视图的自动同步,ViewModel 由 Vue 实例内部实现。 |
MVC | Model ← Controller → View | 单向数据流(用户操作 → Controller → Model → View) | Vue Router 中路由守卫可视为 Controller,处理导航逻辑并更新视图;大型应用中可能拆分出独立的 Model 层(如 API 服务)。 |
MVP | Model ← Presenter → View | 单向数据流(Presenter 作为中介) | Vue 组件中的 props 和 emit 机制类似 MVP,父组件通过 props 传递数据给子组件,子组件通过 emit 通知父组件更新,形成单向数据流。 |
扩展:Vue 中的 MVVM 实现
- 响应式系统:Vue 2 使用
Object.defineProperty
,Vue 3 使用Proxy
实现数据劫持。 - 模板编译:将
template
编译为渲染函数,生成虚拟 DOM。 - 双向绑定:通过
v-model
实现表单元素与数据的双向绑定,本质是:value
+@input
的语法糖。