Vue3 作为目前前端项目的主流技术栈,无论是日常业务开发、工程化项目搭建,还是前端面试,都是必考且核心的技术重点。
很多开发者长期使用 Vue3 开发,但知识点零散、体系混乱,面试时无法系统作答,开发时也容易写出不规范的代码。
本文系统化复盘 30+ Vue3 高频知识点,涵盖组合式API、响应式原理、生命周期、组件通信、性能优化、新特性、避坑指南七大模块,全部为实战高频考点,结构清晰、干货密集,适合收藏复盘、查漏补缺、面试背诵。
一、Vue3 整体核心优势(面试开篇必答)
相比 Vue2,Vue3 在架构、性能、语法、工程化上全面升级,核心优势集中在 5 点:
- 性能大幅提升:重写虚拟 DOM、优化 diff 算法、支持静态提升、预字符化,初始渲染和更新渲染速度更快
- 体积更小:全面模块化、按需引入、Tree-Shaking 友好,打包体积大幅压缩
- 组合式 API:替代 Options 选项式 API,解决大型项目代码碎片化、逻辑分散问题,支持逻辑抽离与复用
- 更强的 TS 支持:源码基于 TS 重写,类型推断完善,大型项目类型约束更严谨
- 全新响应式原理:基于 Proxy 替代 Object.defineProperty,解决 Vue2 响应式底层缺陷
二、组合式 API 核心知识点(开发最常用)
组合式 API 是 Vue3 最大的更新,也是日常开发使用率最高的语法,下面汇总高频核心用法与知识点。
1. setup 函数
- Vue3 组合式 API 的入口函数,组件创建前执行,比生命周期更早
- 无法使用 this,this 指向 undefined
- 内部定义的变量、函数,需要 return 后才可在模板中使用(script setup 语法糖无需手动 return)
- 支持同步写法,不支持 async/await 顶层异步(会阻塞组件渲染)
<script setup>
// 【规范写法】script setup 语法糖
// 无需手动return、无需注册组件,代码极简
let msg = 'Vue3 setup 入门'
function showMsg() {
console.log(msg)
}
</script>
<template>
<div>{{ msg }}</div>
</template>
避坑要点:禁止使用顶层 async setup,会导致组件渲染阻塞
<!-- 错误写法:顶层async,阻塞组件挂载 -->
<script setup async>
const res = await fetch('/api/list')
</script>
2. ref 基础响应式
- 用于定义基本数据类型响应式数据:String、Number、Boolean、Null、Undefined
- 底层通过类实例实现响应式,数据默认包裹在
.value中 - 模板中可省略 .value,JS 逻辑中必须手动书写 .value
- 也可兼容定义对象、数组,但不推荐,性能不如 reactive
<script setup>
import { ref } from 'vue'
// 【正确写法】基础类型使用ref定义响应式
const count = ref(0)
const name = ref('前端复盘')
// JS逻辑中必须通过.value修改值
const add = () => {
count.value++
}
</script>
<template>
<div>
<p>数值:{{ count }}</p>
<p>名称:{{ name }}</p>
<button @click="add">自增</button>
</div>
</template>
错误写法踩坑:基础类型直接定义,无响应式;ref对象直接赋值覆盖响应式
<script setup>
// 错误1:普通变量,非响应式,视图不更新
let num = 10
// 错误2:直接替换ref整个对象,丢失响应
const refNum = ref(0)
refNum = 100
</script>
3. reactive 响应式对象
- 专门用于定义引用类型响应式数据:对象、数组、嵌套复杂数据
- 基于 Proxy 实现,无需 .value,直接访问属性
- 支持深度响应式,默认递归监听所有嵌套属性
- 存在有限性:解构会丢失响应式、直接替换对象会丢失响应式
<script setup>
import { reactive } from 'vue'
// 【正确写法】引用类型使用reactive
const userInfo = reactive({
name: 'Vue3开发者',
age: 24,
address: {
city: '北京'
}
})
// 直接修改属性,无需.value,深度响应式生效
const changeCity = () => {
userInfo.address.city = '上海'
}
</script>
<template>
<div>
<p>城市:{{ userInfo.address.city }}</p>
<button @click="changeCity">切换城市</button>
</div>
</template>
错误写法踩坑:直接替换整个reactive对象、解构赋值,丢失响应式
<script setup>
import { reactive } from 'vue'
const state = reactive({ a: 1, b: 2 })
// 错误1:直接替换整个对象,响应式彻底丢失
// state = reactive({ a: 100 })
// 错误2:直接解构,变量脱离响应式追踪
// const { a } = state
</script>
4. toRefs 解构保留响应式
- 解决 reactive 对象解构丢失响应式问题
- 将 reactive 对象的每一个属性转为独立 ref 对象
- 解构后依然保留双向响应式,是项目高频实用技巧
<script setup>
import { reactive, toRefs } from 'vue'
const state = reactive({
title: 'Vue3复盘',
num: 10
})
// 【错误写法】直接解构,丢失响应式,修改不更新视图
// const { title, num } = state
// 【正确写法】toRefs解构,保留完整响应式
const { title, num } = toRefs(state)
const changeTitle = () => {
title.value = 'Vue3知识点汇总'
}
</script>
<template>
<div>{{ title }} - {{ num }}</div>
</template>
5. toRef 精准创建属性响应式
- 单独针对对象某个属性创建响应式引用
- 适用于只需要监听单个属性、无需解构全部数据的场景
<script setup>
import { reactive, toRef } from 'vue'
const info = reactive({
a: 1,
b: 2,
c: 3
})
// 【正确写法】单独绑定对象属性,保留响应式引用
const a = toRef(info, 'a')
const updateA = () => {
a.value += 1
}
</script>
<template>
<div>{{ a }}</div>
</template>
错误写法踩坑:直接赋值属性,属于普通变量,无响应联动
<script setup>
// 错误:只是普通数值拷贝,和原对象无联动
const a = info.a
a++ // 视图不更新,原对象值不变
</script>
6. computed 计算属性
- 具备缓存机制,依赖不变则不重复计算,优于方法调用
- 分为只读计算属性、可写计算属性
- 自动收集依赖,依赖更新自动触发更新
<script setup>
import { ref, computed } from 'vue'
const price = ref(99)
const count = ref(2)
// 【正确1】只读计算属性(业务最常用)
const totalPrice = computed(() => {
return price.value * count.value
})
// 【正确2】可写计算属性
const doubleCount = computed({
get() {
return count.value * 2
},
set(val) {
count.value = val / 2
}
})
</script>
<template>
<div>总价:{{ totalPrice }}</div>
</template>
错误写法踩坑:用普通方法替代计算属性,无缓存,频繁重复计算,性能差
<script setup>
// 错误:每次渲染都会执行,无缓存,性能浪费
const getTotal = () => {
return price.value * count.value
}
</script>
7. watch / watchEffect 监听机制
- watch:精准监听指定数据,支持新旧值、深度监听、立即执行
- watchEffect:自动收集依赖,无需手动传入监听源,立即执行、自动响应
- watch 适合精准监听单一数据,watchEffect 适合多依赖自动监听场景
<script setup>
import { ref, reactive, watch, watchEffect } from 'vue'
const num = ref(0)
const user = reactive({ name: '张三', age: 20 })
// 【正确1】精准监听基础类型
watch(num, (newVal) => {
console.log('数值更新:', newVal)
})
// 【正确2】监听复杂对象,开启立即执行+深度监听
watch(user, () => {
console.log('用户信息更新')
}, { immediate: true, deep: true })
// 【正确3】watchEffect自动收集多依赖
watchEffect(() => {
console.log('自动监听数据:', num.value, user.name)
})
</script>
错误写法踩坑:监听reactive对象不开启deep,嵌套属性更新不触发监听
<script setup>
// 错误:未开启deep,嵌套属性更新无法监听
watch(user, () => {
console.log('更新')
})
user.age = 25 // 不触发监听回调
</script>
三、Vue3 生命周期知识点
Vue3 生命周期兼容 Vue2 写法,同时提供组合式 API 钩子,核心常用钩子 8 个,面试高频考察执行顺序。
- onBeforeCreate / onCreated:组件创建阶段,setup 替代大部分逻辑
- onBeforeMount / onMounted:DOM 挂载前后,异步请求、DOM 操作放在 onMounted
- onBeforeUpdate / onUpdated:数据更新、DOM 重渲染前后
- onBeforeUnmount / onUnmounted:组件销毁前后,用于清除定时器、监听事件、解绑全局监听
<script setup>
import { onMounted, onUpdated, onUnmounted } from 'vue'
let timer = null
// 【正确】DOM挂载后请求接口、初始化数据、开启定时器
onMounted(() => {
console.log('组件挂载完成')
timer = setInterval(() => {}, 1000)
})
// 数据更新DOM完成后执行
onUpdated(() => {
console.log('组件更新完成')
})
// 【正确】组件销毁,清除副作用,防止内存泄漏
onUnmounted(() => {
clearInterval(timer)
timer = null
console.log('组件销毁,清除定时器')
})
</script>
错误写法踩坑:所有逻辑堆在setup顶层、不清除副作用
<script setup>
// 错误1:顶层直接请求,执行时机不可控
// 错误2:不清除定时器,页面销毁内存泄漏
setInterval(() => {}, 1000)
</script>
核心考点:Vue3 取消了 beforeCreate、created,统一在 setup 中编写初始化逻辑;销毁钩子更名(destroyed → unmounted)。
四、Vue3 组件通信全方案(高频业务+面试)
Vue3 废弃了 Vue2 的 listeners、事件总线等部分 API,提供更规范、更安全的通信方式,全覆盖 8 种通信方案。
1. 父子通信:props / defineProps
父传子核心方案,支持类型校验、默认值、必填校验,Vue3 推荐使用 defineProps 语法糖。
// 子组件 【正确写法】规范校验+默认值
<script setup>
const props = defineProps({
title: {
type: String,
default: '默认标题'
},
list: {
type: Array,
default: () => [] // 引用类型必须函数返回
}
})
</script>
// 父组件使用
<Child title="Vue3复盘" :list="[1,2,3]" />
错误写法踩坑:引用类型默认值直接写死,所有组件实例共享数据
<script setup>
// 错误:数组默认值字面量,多组件数据污染
const props = defineProps({
list: {
type: Array,
default: []
}
})
</script>
2. 子父通信:emit / defineEmits
子组件通过 defineEmits 自定义事件,向上传递数据,替代 Vue2 this.$emit。
// 子组件【正确写法】
<script setup>
// 声明自定义事件
const emit = defineEmits(['sendData'])
const send = () => {
emit('sendData', '子组件传递的数据')
}
</script>
// 父组件接收
<Child @sendData="handleData" />
<script setup>
const handleData = (res) => {
console.log('接收子组件数据:', res)
}
</script>
错误写法踩坑:script setup 中直接使用 this.$emit(Vue3语法失效)
<script setup>
// 错误:setup无this,直接报错
this.$emit('sendData', '测试')
</script>
3. 双向绑定:defineModel(Vue3.4+ 新特性)
极简实现组件双向绑定,无需 props+emit 繁琐写法,封装弹窗、输入框组件必备。
// 子组件【正确写法】Vue3.4+ defineModel 极简双向绑定
<script setup>
const modelValue = defineModel()
</script>
<template>
<input v-model="modelValue" placeholder="双向绑定输入" />
</template>
// 父组件使用
<script setup>
const inputVal = ref('')
</script>
<template>
<Child v-model="inputVal" />
</template>
旧写法(繁琐不推荐) :传统props+emit冗余实现双向绑定
// 老旧冗余写法,现已废弃
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const change = (val) => {
emit('update:modelValue', val)
}
4. 祖先后代通信:provide / inject
跨多层级组件传值,无需逐层透传,适合全局配置、主题、权限、用户信息透传。
// 【正确】祖先组件注入数据
<script setup>
import { provide, ref } from 'vue'
// 传递响应式数据,后代可联动更新
const theme = ref('dark')
provide('theme', theme)
provide('userName', '超级管理员')
</script>
// 【正确】任意后代组件接收
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
const userName = inject('userName')
</script>
错误写法踩坑:传递普通静态值,后代无法响应更新
<script setup>
// 错误:传递普通字符串,非响应式,修改不联动
provide('theme', 'light')
</script>
5. 组件实例获取:defineExpose
Vue3 组件默认关闭实例暴露,父组件想要调用子组件方法、获取子组件数据,必须通过 defineExpose 主动暴露。
// 子组件【正确写法】主动暴露实例和方法
<script setup>
const msg = '子组件数据'
const childFn = () => console.log('执行子组件方法')
// 主动暴露,父组件才可调用
defineExpose({ msg, childFn })
</script>
// 父组件【正确写法】
<script setup>
import { ref } from 'vue'
const childRef = ref(null)
const callChild = () => {
childRef.value.childFn()
}
</script>
<template>
<Child ref="childRef" />
</template>
错误写法踩坑:不写defineExpose,父组件获取不到子组件数据和方法
<script setup>
// 子组件未暴露任何内容
const childFn = () => {}
// 父组件调用直接报错
// childRef.value.childFn() 【undefined】
</script>
6. 全局状态通信:Pinia
Vue3 官方替代 Vuex 的状态管理库,轻量化、简洁、模块化、无嵌套,支持 TS、自动持久化,是项目全局状态共享首选方案。
// 1. 新建 store/user.js 状态仓库
import { defineStore } from 'pinia'
// 定义用户全局仓库
export const useUserStore = defineStore('user', {
// 状态
state: () => ({
userName: '',
token: '',
userId: ''
}),
// 计算属性
getters: {
isLogin: (state) => !!state.token
},
// 同步/异步方法
actions: {
// 存储用户信息
setUserInfo(data) {
this.userName = data.userName
this.token = data.token
this.userId = data.userId
},
// 清空用户信息
clearUserInfo() {
this.$reset()
}
}
})
// 2. 组件内使用 Pinia 状态
<script setup>
import { useUserStore } from '@/store/user'
// 初始化仓库
const userStore = useUserStore()
// 赋值修改全局状态
const setUser = () => {
userStore.setUserInfo({
userName: 'Vue3开发者',
token: 'xxxx-xxxx-xxxx',
userId: '10001'
})
}
// 清空状态
const clearUser = () => {
userStore.clearUserInfo()
}
</script>
<template>
<div>
<p>用户名:{{ userStore.userName }}</p>
<button @click="setUser">登录赋值</button>
<button @click="clearUser">清空信息</button>
</div>
</template>
7. 插槽通信:slot / 作用域插槽
默认插槽、具名插槽实现内容分发,作用域插槽实现子传父数据渲染,高阶组件封装必备。
// 子组件
<template>
<!-- 作用域插槽向外传递数据 -->
<slot :msg="hello vue3"></slot>
</template>
// 父组件
<template>
<Child v-slot="scope">
{{ scope.msg }}
</Child>
</template>
8. 兄弟组件通信:Pinia / 自定义事件
Vue3 不推荐事件总线,统一使用 Pinia 实现兄弟组件状态共享,稳定易维护。
五、Vue3 响应式原理核心考点(面试重中之重)
1. 底层原理 Proxy
Vue3 使用Proxy + Reflect 实现响应式,替代 Vue2 Object.defineProperty,解决大量底层缺陷。
2. Proxy 对比 defineProperty 优势
- 可监听数组新增、删除、下标修改、长度修改
- 可监听对象新增、删除属性
- 支持批量拦截、更完善的拦截能力
- 无需递归遍历初始对象,性能更优
3. 三大核心机制
- 依赖收集:数据读取时收集当前组件渲染副作用
- 依赖追踪:数据变更触发对应的更新函数
- 派发更新:通知视图更新、执行监听与计算属性回调
4. 响应式丢失常见场景
- reactive对象直接解构:丢失响应式
- 直接替换reactive对象:丢失响应式
- 数组下标/长度直接修改:部分场景不更新视图
- 普通函数接收响应式数据:丢失响应式绑定
<script setup>
import { reactive, toRefs } from 'vue'
const state = reactive({ a: 1, b: 2 })
// ========== 错误写法(全部踩坑)==========
// 坑1:直接解构,丢失响应式
// const { a } = state
// 坑2:直接替换整个对象,响应式销毁
// state = reactive({ a: 100 })
// 坑3:数组下标直接修改,部分场景不更新视图
// const arr = reactive([1,2,3])
// arr[0] = 99
// ========== 正确写法(规范稳定)==========
const { a, b } = toRefs(state)
a.value = 99 // 响应式正常更新
六、Vue3 编译与性能优化知识点
1. 虚拟 DOM 重写
Vue3 重构虚拟 DOM,优化 diff 算法,对比层级更精准、补丁更少、更新更快。
2. 静态提升
编译阶段将静态不变节点提升到渲染函数外部,避免每次渲染重新创建 VNode,大幅提升性能。
3. 预字符化
连续静态文本合并为常量字符串,减少虚拟 DOM 节点数量,降低内存占用。
4. 缓存事件处理函数
Vue3 自动缓存模板事件函数,避免每次更新生成新函数,减少不必要的 diff 更新。
5. 按需引入 Tree-Shaking
Vue3 全量模块化导出,未使用的 API 可被打包工具剔除,大幅缩减打包体积。
七、Vue3 高频实用新特性知识点
- SFC 语法糖升级:script setup 语法,代码更简洁、无需手动 return、自动注册组件,简化组件开发逻辑
- CSS 变量注入:v-bind() 可在 CSS 中使用 JS 变量,实现动态样式、主题切换、动态尺寸等高阶样式需求
<script setup>
import { ref } from 'vue'
// 定义JS动态变量
const textColor = ref('#4096ff')
</script>
<template>
<div class="box">Vue3动态样式</div>
</template>
<style scoped>
.box {
color: v-bind(textColor);
}
</style>
错误写法踩坑:CSS 无法直接读取 JS 变量,不使用 v-bind 绑定,动态样式不生效
<style scoped>
/* 错误:无法识别JS变量textColor */
.box {
color: textColor;
}
</style>
- 多根节点支持:Vue3 摒弃 Vue2 唯一根节点限制,默认支持 Fragment 虚拟片段,减少多余 DOM 层级,精简页面结构
- Teleport 传送门:脱离当前组件DOM层级,将节点挂载到任意指定DOM位置,完美解决弹窗、遮罩、悬浮层层级穿透问题
- Suspense 异步兜底:内置异步组件加载兜底方案,无需手动写loading状态,优化异步组件加载体验
- defineProps 默认值写法优化:Vue3.3+ 提供 withDefaults 语法糖,完美支持TS类型推导,简洁规范设置props默认值
- 自定义指令生命周期更新:Vue3 指令钩子与组件生命周期对齐,废弃Vue2旧钩子,逻辑更统一,避免执行异常
八、Vue3 开发高频避坑知识点
- reactive 不支持基础类型,基础类型必须用 ref
- reactive 解构直接丢失响应式,必须配合 toRefs
- setup 中无 this,无法使用 Vue2 原型方法
- 组件默认不暴露实例,必须 defineExpose 才可被父组件调用
- watch 监听 reactive 对象必须开启 deep 深度监听
- 异步请求写在 onMounted,不要写在 setup 同步顶层大量逻辑
- 定时器、事件监听必须在 onUnmounted 中清除,防止内存泄漏
- script setup 中组件自动注册,但全局组件仍需全局注册
九、知识点总结
本次复盘汇总的 30+ Vue3 核心知识点,覆盖:
- 基础语法:ref / reactive / computed / watch
- 生命周期与组件执行机制
- 八大组件通信方案
- Proxy 响应式底层原理
- 编译优化与性能提升机制
- 高频新特性与实战避坑指南
这些知识点既是日常开发必备基础,也是面试高频核心考点,熟练掌握可以彻底打通 Vue3 知识体系,告别只会写业务不懂原理、知识点零散的问题。