Appearance
Vue3 (核心重点)
本章管什么:Vue3 怎么写——Proxy / ref / reactive、setup、生命周期写法、组件传值 API、Pinia 用法、框架内性能手段。
本章不管什么:为什么选 Vue3、和 Vue2 的选型对比 → 架构 · Vue2 vs Vue3;项目级性能四块清单 → 工程化 · 性能。
Vue3 相比 Vue2 有哪些核心优化和区别?
这里是能力清单(方便对照 API)。面试问「为什么换 3 / 怎么选」用 架构 那套口述。
| 方向 | Vue3 变化 |
|---|---|
| 响应式 | Proxy 替代 defineProperty |
| API | Composition API,逻辑按功能聚合 |
| 性能 | 编译优化(静态提升、补丁标记)、更小的包(tree-shake) |
| TS | 对 TypeScript 更友好 |
| 碎片 | Fragments 多根节点、Teleport、Suspense |
| 兼容 | 部分写法 breaking,Vue2 选项式仍可用 |
🎤 口述精简版
Vue3 核心是 Proxy 响应式、Composition API、编译期优化和更好的 TS 支持,还有 Teleport 这些新能力。
Vue3 双向绑定原理?Proxy 相比 Object.defineProperty 的优势?
原理仍是:劫持依赖收集 + 触发更新;v-model 仍是属性 + 事件。底层改成 Proxy 代理整个对象。
Proxy 相比 Object.defineProperty 好在哪
原理没换:还是劫持 → 依赖收集 → 改了通知更新。换的是劫持方式。
Object.defineProperty(Vue2) | Proxy(Vue3) | |
|---|---|---|
| 怎么包 | 给已有属性逐个加 getter / setter | 代理整个对象 |
| 新增 / 删除 | 侦不到,要 Vue.set / Vue.delete | 能侦到 |
| 数组 | 下标、length 不直观,靠重写 push 等 | 更自然 |
| 嵌套 | 初始化常递归全包 | 用到再代理,更省 |
🎤 口述精简版
Vue3 用 Proxy 做响应式,比 Vue2 的 defineProperty 好用:增删能侦到、数组自然、懒代理更省。细节见上表。
ref 和 reactive 的区别?各自使用场景?为什么 ref 需要 .value?
ref | reactive | |
|---|---|---|
| 适用 | 基本类型 + 对象都行 | 主要是对象/数组 |
| 访问 | 脚本里 .value | 直接用属性 |
| 替换 | 换整个值方便 | 整体替换要小心丢掉代理 |
场景:简单值用 ref;结构清晰的对象用 reactive;不确定时统一 ref 也常见。
为什么要 .value:ref 把值包在对象里,才能对基本类型保持响应式;模板里会自动解包,脚本里要 .value。
🎤 口述精简版
ref 万能但脚本要 .value;reactive 直接解构属性要小心丢响应式。简单值用 ref,对象可用 reactive。
setup 函数的执行时机、特点?
- 在
beforeCreate之前同步执行(组件实例创建时) - 没有
this(还没建立组件实例那套选项式 this) - 接收
props、context - 返回的东西可供模板使用(
<script setup>则自动暴露)
🎤 口述精简版
setup 最早执行,没有 this,用来放组合式逻辑;现在更多直接写 <script setup>。
<script setup> 语法糖的优势和用法?
优势:
- 少写
setup()return - 顶层绑定自动给模板用
- 更好用的
defineProps/defineEmits - 运行时更利于编译优化、写起来短
vue
<script setup lang="ts">
import Hello from './Hello.vue'
const count = ref(0)
</script>🎤 口述精简版
<script setup> 是组合式写法的糖,不用手动 return,props/emits 也好写,现在 Vue3 项目标配。
defineProps、defineEmits、defineExpose 的作用和使用方式?
| API | 作用 |
|---|---|
defineProps | 声明 props |
defineEmits | 声明向父组件触发的事件 |
defineExpose | 显式暴露给父组件 $refs 用的方法/数据 |
它们是编译器宏,不必 import。
ts
const props = defineProps<{ title: string }>()
const emit = defineEmits<{ click: [] }>()
defineExpose({ open })🎤 口述精简版
setup 语法里:defineProps 收参,defineEmits 发事件,defineExpose 把方法暴露给父级 ref。
Vue3 组件怎么传值?和 Vue2 比写法上变了什么?
按关系还是那一套:父子、兄弟、跨多层、全局。变的是 API。
| 场景 | Vue3 怎么写 |
|---|---|
| 父 → 子 | defineProps(选项式仍可用 props) |
| 子 → 父 | defineEmits;没有 $on / $off,实例不能当 bus |
| 父调子方法 | 子 defineExpose,父 $refs |
| 跨多层 | provide / inject 仍在,值要用 ref 才响应式 |
| 全局 | Pinia,不再上 Vuex |
| 透传 | $attrs 含类、未声明 props,也含监听(Vue2 的 $listeners 并进来了) |
组件 v-model | 默认 modelValue + update:modelValue |
兄弟仍找共同父中转。指令、v-if / v-show、路由 query / params 和 Vue2 同一套,不必另答。
🎤 口述精简版
传值关系没变。组合式用 defineProps / defineEmits,父调子要 defineExpose。没有事件总线 $on。全局换 Pinia。v-model 默认 modelValue。
computed 和 watch 的区别?各自使用场景?
computed | watch | |
|---|---|---|
| 定位 | 由依赖算出新值 | 侦听变化做副作用 |
| 缓存 | 有缓存,依赖不变不重算 | 每次变都可执行 |
| 返回 | 返回值给模板/逻辑用 | 一般不求返回值 |
场景:派生展示用 computed;请求、打点、同步存储用 watch。
🎤 口述精简版
computed 算值有缓存;watch 盯着变化干活。能 computed 就别滥用 watch。
watch 和 watchEffect 的区别?
watch | watchEffect | |
|---|---|---|
| 依赖 | 要明确指明侦听源 | 自动收集回调里用到的响应式依赖 |
| 旧值 | 能拿到新旧值 | 默认更偏「立即跑 + 收集依赖」 |
| 懒执行 | 默认数据变才跑(可 immediate) | 一上来先执行一次 |
🎤 口述精简版
watch 精确指定听谁,能比新旧值;watchEffect 自动追依赖,上来先跑一遍,适合简单副作用。
Pinia 相比 Vuex 的优势?Pinia 核心使用流程?怎么持久化?
优势
- API 更简单,去掉 mutation,直接 action 改 state
- TS 支持好
- 模块天然拆分(每个 store 一个)
- 体积小,和 Composition 风格一致
使用流程
createPinia()挂到 appdefineStore定义 store- 组件里调用
useXxxStore()读写
ts
export const useUserStore = defineStore('user', {
state: () => ({ token: '' }),
actions: {
setToken(t: string) { this.token = t }
}
})持久化
和 Vuex 同一思路:Pinia 也在内存里,刷新会空。token、用户信息存 localStorage,启动时灌回;或用 pinia-plugin-persistedstate 选 store 持久化。列表详情进页再请求。
🎤 口述精简版
Pinia 是 Vue3 官方推荐状态库,比 Vuex 简单,没有 mutation,TS 友好。defineStore 定义,组件里 useStore 使用。持久化和 Vuex 一样:登录态存本地再灌回,业务数据进页再请求。
Vue3 生命周期与 Vue2 的区别?组合式 API 生命周期写法?
选项式名字大体还在,但销毁改成 beforeUnmount / unmounted。
组合式用 onXxx:
| Vue2 | Vue3 组合式 |
|---|---|
beforeMount | onBeforeMount |
mounted | onMounted |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
setup 本身相当于 beforeCreate + created 时段。
🎤 口述精简版
Vue3 销毁钩子改名 unmount;组合式写成 onMounted、onBeforeUnmount 这种,在 setup 里调用。
Vue3 Teleport、Suspense 的作用和使用场景?
Teleport:把子组件 DOM 渲染到别的容器(如 body),逻辑仍在当前组件树。场景:弹窗、遮罩,避免 overflow、层级问题。
Suspense:等待异步依赖(异步组件 / async setup)时展示 fallback。场景:异步组件加载中的占位。
🎤 口述精简版
Teleport 解决弹层挂载位置;Suspense 解决异步组件加载时的兜底展示。
Vue3 动态路由权限如何实现?
常见流程:
- 登录拿到角色/权限菜单
- 前端按权限表生成路由(或后端直接返回路由结构)
router.addRoute动态添加- 全局
beforeEach校验登录与权限 - 404 路由最后加;注意刷新后要重新加动态路由(常在守卫里判断是否已 add)
🎤 口述精简版
权限路由一般是登录后拿权限,动态 addRoute,再用全局守卫拦无权限访问;刷新要重新注入动态路由。
Vue3 如何解决 setup 中 this 指向问题?
setup 里没有选项式的 this。解决方式:不要依赖 this——用 ref/reactive、props、composables;需要实例时用 getCurrentInstance()(慎用)。
<script setup> 更彻底,基本告别 this。
🎤 口述精简版
setup 没有 this,用响应式 API 和 props 即可;别强行找 this,那是选项式思维。
Vue3 项目性能优化有哪些方案?
偏 Vue / 组件层。加载 / 打包 / 网络级手段见 工程化 · 性能。
- 路由/组件懒加载,
defineAsyncComponent v-once/v-memo减少更新- 合理拆组件,props 稳定,避免多余响应式
- 大列表虚拟滚动
shallowRef/markRaw处理大对象、第三方实例- 打包分析、拆包、压缩资源
- keep-alive 缓存常用页
- 少在父组件塞过大 reactive 对象导致无关更新
🎤 口述精简版
Vue3 性能优化:懒加载、虚拟列表、减少响应式范围、v-memo、keep-alive,再加上常规打包和资源优化。