Vue3面试核心问题

目录


Vue3新特性

1. Vue3有哪些新特性?

参考答案:

新特性 说明
Composition API 组合式API,更灵活的代码组织
Proxy响应式 替代Object.defineProperty
Teleport 传送到任意DOM
Suspense 异步组件加载状态
Fragment 多根节点组件
Tree-shaking 更多API按需引入
更小更快 优化后的打包体积
TypeScript 完整类型系统支持
自定义渲染器 自定义渲染API

2. setup函数是什么?

参考答案:

setup是Vue3新增的入口函数,在beforeCreate之前执行:

1
2
3
4
5
6
7
8
9
10
11
export default {
setup() {
// this是undefined
const count = ref(0)

// setup需要返回对象才能在模板中使用
return {
count
}
}
}

执行时机:

  • 在beforeCreate之前执行
  • 每当props更新后会重新执行
  • 不能使用this

3. script setup是什么?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
// 编译器自动转换为setup函数内容
import { ref } from 'vue'

const count = ref(0)

// 导入的组件自动注册
import MyComponent from './MyComponent.vue'

// 顶层变量和函数直接在模板使用
function increment() {
count.value++
}
</script>

优势:

  • 更简洁的代码
  • 自动推断类型
  • 更好的性能

4. Teleport是什么?

参考答案:

Teleport可以将组件渲染到任意DOM位置:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<teleport to="body">
<div class="modal">
<p>模态框内容</p>
</div>
</teleport>
</template>

<!-- 条件控制 -->
<teleport to="body" :disabled="!isShow">
<div v-if="isShow" class="modal">内容</div>
</teleport>

5. Suspense是什么?

参考答案:

Suspense用于异步组件加载状态:

1
2
3
4
5
6
7
8
9
10
<template>
<suspense>
<template #default>
<async-component />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</suspense>
</template>

Composition API

6. ref和reactive的区别?

参考答案:

对比 ref reactive
适用类型 基本类型 对象/数组
访问方式 .value 直接访问
解构 丢失响应式(需toRefs) 丢失响应式
重新赋值 会响应式更新 会响应式更新
内部实现 对象包装 Proxy代理
1
2
3
4
5
6
7
// ref - 适合基本类型
const count = ref(0)
count.value++

// reactive - 适合对象
const state = reactive({ count: 0 })
state.count++

7. toRefs的作用?

参考答案:

toRefs用于将reactive对象转换为普通对象,保持响应式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const state = reactive({
count: 0,
name: '张三'
})

// 解构后仍然响应式
const { count, name } = toRefs(state)

// 或
const stateAsRefs = toRefs(state)

// 修改
count.value++
name.value = '李四'

8. computed和watch的区别?

参考答案:

对比 computed watch
用途 计算属性 监听数据变化
返回值 必须有 可有可无
缓存
执行时机 被动响应 主动监听
适用场景 同步计算 异步/副作用
1
2
3
4
5
6
7
8
9
10
11
12
// computed - 自动收集依赖
const doubled = computed(() => count.value * 2)

// watch - 明确监听
watch(count, (newVal, oldVal) => {
console.log(newVal, oldVal)
})

// watchEffect - 自动收集依赖,立即执行
watchEffect(() => {
console.log(count.value)
})

9. watch和watchEffect的区别?

参考答案:

对比 watch watchEffect
依赖收集 手动指定 自动收集
立即执行 需要immediate 默认立即执行
访问旧值 可以 不可以
首次执行 可能不执行 立即执行
适用场景 精确控制 副作用操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// watch - 惰性执行,需要手动开启immediate
watch(count, (newVal, oldVal) => {
// 首次不执行
})

// watch - 立即执行
watch(count, (newVal, oldVal) => {
// 首次执行
}, { immediate: true })

// watchEffect - 非惰性,自动收集
watchEffect(() => {
console.log(count.value)
// 立即执行
})

10. provide/inject的使用场景?

参考答案:

用于跨级组件通信:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 祖先组件
import { provide, ref } from 'vue'

export default {
setup() {
const theme = ref('dark')
provide('theme', theme)

// 跨组件修改
function updateTheme() {
theme.value = 'light'
}
provide('updateTheme', updateTheme)
}
}

// 后代组件
import { inject } from 'vue'

export default {
setup() {
const theme = inject('theme')
const updateTheme = inject('updateTheme')

return { theme, updateTheme }
}
}

响应式原理

11. Vue3响应式原理是什么?

参考答案:

Vue3使用Proxy实现响应式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const proxy = new Proxy(data, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
track(target, key) // 依赖收集
return typeof res === 'object' ? reactive(res) : res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
trigger(target, key) // 触发更新
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
trigger(target, key)
return res
}
})

12. Proxy相比Object.defineProperty的优势?

参考答案:

优势 说明
监听整个对象 无需递归
监听新增属性 自动响应
监听删除属性 自动响应
监听数组索引 自动响应
支持Map/Set 新的数据结构
更好的性能 一次代理

13. 什么是依赖收集?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Vue3依赖收集机制
class ReactiveEffect {
constructor(fn) {
this.fn = fn
this.deps = []
}

run() {
activeEffect = this
this.fn()
activeEffect = null
}
}

// track - 收集依赖
function track(target, key) {
if (activeEffect) {
targetMap.get(target).get(key).add(activeEffect)
activeEffect.deps.push(targetMap.get(target).get(key))
}
}

// trigger - 触发更新
function trigger(target, key) {
targetMap.get(target).get(key).forEach(effect => effect.run())
}

14. readonly和shallowReactive?

参考答案:

API 说明
reactive 深层响应式
shallowReactive 浅层响应式
ref 深层响应式(基本类型)
shallowRef 浅层响应式
readonly 只读响应式
shallowReadonly 浅层只读
1
2
3
4
5
6
7
8
9
10
11
// shallowReactive - 只代理第一层
const state = shallowReactive({
count: 0,
deep: { name: '张三' }
})
state.deep.name = '李四' // 不响应

// shallowRef - 只有.value变化才响应
const list = shallowRef([])
list.value.push(1) // 不响应
list.value = [1] // 响应

15. 如何追踪Vue3的响应式依赖?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { watchEffect, onRenderTracked, onRenderTriggered } from 'vue'

export default {
onMounted() {
// 每次渲染后追踪响应式依赖
onRenderTracked((event) => {
console.log('追踪:', event)
// event.target / event.key / event.type
})

// 每次依赖变化触发更新
onRenderTriggered((event) => {
console.log('触发:', event)
})
}
}

与Vue2对比

16. Vue3生命周期有哪些变化?

参考答案:

Vue2 Vue3 说明
beforeCreate setup 替代
created setup 替代
beforeMount onBeforeMount -
mounted onMounted -
beforeUpdate onBeforeUpdate -
updated onUpdated -
beforeDestroy onBeforeUnmount 改名
destroyed onUnmounted 改名
errorCaptured onErrorCaptured -
- onRenderTracked 新增
- onRenderTriggered 新增

17. Vue3全局API有哪些变化?

参考答案:

Vue2 Vue3 说明
Vue.config app.config -
Vue.component app.component -
Vue.directive app.directive -
Vue.mixin app.use 移除,使用插件
Vue.use app.use -
Vue.prototype app.config.globalProperties -
Vue.filter - 移除

18. Vue3性能提升有哪些?

参考答案:

提升点 说明
打包体积 约10KB,比Vue2小
渲染速度 虚拟DOM重写,更快
更新性能 Proxy响应式,更精准
内存占用 优化后更小
编译优化 Block tree,静态提升

19. Vue3 Diff算法有什么优化?

参考答案:

Vue3的Diff算法优化:

  1. 静态提升: 静态节点不参与diff
  2. Patch flags: 标记动态节点
  3. Block tree: 区块树优化
  4. hoistStatic: 静态提升减少重复创建
1
2
3
4
5
6
7
8
9
10
11
12
13
┌─────────────────────────────────────────────────────────────┐
│ Vue3 Block Tree │
├─────────────────────────────────────────────────────────────┤
│ │
│ 静态节点直接提升,不参与diff │
│ │
│ <div> div (block) │
│ <p>静态内容</p> --> ├─ p (hoisted) │
│ <span>{{msg}}</span> ├─ span (patch flag) │
│ <span>{{msg}}</span> └─ span (patch flag) │
│ </div> │
│ │
└─────────────────────────────────────────────────────────────┘

20. Vue3的Tree-shaking如何实现?

参考答案:

Vue3支持Tree-shaking,可以排除未使用的功能:

1
2
3
4
5
6
7
8
// 按需引入
import { ref, computed, watch } from 'vue'

// 未使用的API不会被打包
// 例如:Transition组件

// 应用
import { Transition } from 'vue'

实战问题

21. 如何在Vue3中使用Vue2的Options API?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export default {
// Vue2的Options API仍然可用
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
computed: {
doubled() {
return this.count * 2
}
},

// Vue3 Composition API
setup() {
const count = ref(0)
return { count }
}
}

22. 如何实现逻辑复用?

参考答案:

Vue3使用Composables(组合式函数)实现逻辑复用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
const x = ref(0)
const y = ref(0)

function update(e) {
x.value = e.pageX
y.value = e.pageY
}

onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))

return { x, y }
}

// 使用
import { useMouse } from './useMouse'

export default {
setup() {
const { x, y } = useMouse()
return { x, y }
}
}

23. 如何处理异步组件错误?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 方式1: errorComponent
const AsyncComp = defineAsyncComponent({
loader: () => import('./AsyncComp.vue'),
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})

// 方式2: onErrorCaptured
import { onErrorCaptured } from 'vue'

export default {
setup() {
onErrorCaptured((err) => {
console.error('捕获到错误:', err)
return false // 阻止冒泡
})
}
}

24. Vue3如何实现CSS变量主题切换?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// App.vue
import { provide, ref, computed } from 'vue'

export default {
setup() {
const theme = ref('light')

const themeVars = computed(() => {
if (theme.value === 'dark') {
return {
'--bg-color': '#1a1a1a',
'--text-color': '#fff'
}
}
return {
'--bg-color': '#fff',
'--text-color': '#000'
}
})

provide('theme', theme)

return { theme, themeVars }
}
}
1
2
3
4
5
6
<!-- Child.vue -->
<template>
<div class="box" :style="themeVars">
内容
</div>
</template>

25. Vue3中如何操作DOM?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div ref="domRef">内容</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const domRef = ref(null)

onMounted(() => {
console.log(domRef.value) // DOM元素
domRef.value.style.color = 'red'
})
</script>

26. 如何升级Vue2项目到Vue3?

参考答案:

步骤 说明
1. 评估依赖 检查Vue插件兼容性
2. Vue CLI迁移 使用迁移工具
3. 全局API 更新为app.config
4. 过滤器 移除,使用方法替代
5. 组件 支持多根节点
6. 生命周期 更新为Composition API
7. 测试 确保功能正常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Vue2
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

// Vue3
import { createApp } from 'vue'

const app = createApp(App)
app.use(router)
app.use(store)
app.mount('#app')

27. Vue3的v-memo是什么?

参考答案:

v-memo用于缓存模板子树:

1
2
3
4
5
6
7
8
9
10
11
<!-- 只有valueA或valueB变化时才更新 -->
<div v-memo="[valueA, valueB]">
<p>{{ valueA }}</p>
<p>{{ valueB }}</p>
<p>{{ valueC }}</p> <!-- valueC变化也会更新 -->
</div>

<!-- 列表优化 -->
<div v-for="item in list" :key="item.id" v-memo="[item.id, item.status]">
<p>{{ item.content }}</p>
</div>

28. defineProps和defineEmits是什么?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script setup>
// 编译器宏,自动转换为setup函数内容
const props = defineProps({
title: String,
count: {
type: Number,
default: 0
}
})

const emit = defineEmits<{
(e: 'update', value: string): void
(e: 'delete', id: number): void
}>()

// 使用
emit('update', 'new value')
</script>

29. Vue3中的setup语法糖有哪些?

参考答案:

语法糖 说明
defineProps 定义props
defineEmits 定义emit
defineExpose 暴露组件属性
useSlots 获取slots
useAttrs 获取attrs
withDefaults props默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { useSlots, useAttrs } from 'vue'

defineProps({
title: String
})

defineExpose({
method: () => console.log('exposed')
})

const slots = useSlots()
const attrs = useAttrs()
</script>

30. Vue3的TransitionGroup有什么变化?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<transition-group name="list">
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</transition-group>
</template>

<style>
.list-enter-active,
.list-leave-active {
transition: all 0.3s;
}

.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}

.list-move {
transition: transform 0.3s;
}
</style>

总结

Vue3核心知识图谱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌─────────────────────────────────────────────────────────────┐
│ Vue3 核心知识图谱 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基础 │
│ ├── Composition API (setup/ref/reactive/computed) │
│ ├── 响应式API (toRefs/toRaw/isRef/isReactive) │
│ └── 生命周期 (onXxx) │
│ │
│ 组件 │
│ ├── Teleport / Suspense / Fragment │
│ ├── 组件通信 (props/emit/provide/inject) │
│ └── 插槽 (默认/具名/动态) │
│ │
│ 原理 │
│ ├── Proxy响应式原理 │
│ ├── 依赖收集与触发 │
│ ├── Block Tree优化 │
│ └── Tree-shaking支持 │
│ │
│ 生态 │
│ ├── Vue Router 4 │
│ ├── Pinia │
│ ├── Vite │
│ └── Nuxt 3 │
│ │
└─────────────────────────────────────────────────────────────┘

面试高频问题TOP10

排名 问题
1 ref和reactive的区别
2 Vue3响应式原理
3 Composition API优势
4 setup函数执行时机
5 watch和watchEffect
6 Vue3生命周期变化
7 Proxy相比Object.defineProperty的优势
8 Teleport和Suspense
9 Vue3性能优化
10 逻辑复用方式

相关链接