目录
[1. 响应式原理不同(最重要)](#1. 响应式原理不同(最重要))
[2. 写法不同(最明显)](#2. 写法不同(最明显))
[3. 生命周期变化](#3. 生命周期变化)
[4. 性能提升](#4. 性能提升)
[5. 其他重要区别](#5. 其他重要区别)
[5.1 多根节点(Fragment)](#5.1 多根节点(Fragment))
[5.2 Teleport(传送门)](#5.2 Teleport(传送门))
[5.3 Suspense(异步组件)](#5.3 Suspense(异步组件))
[5.4 根实例创建方式](#5.4 根实例创建方式)
[5.5 移除的 API](#5.5 移除的 API)
[三、setup 提供的核心优势](#三、setup 提供的核心优势)
[四、setup 怎么用?](#四、setup 怎么用?)
[4.1 传统写法(setup 函数)](#4.1 传统写法(setup 函数))
[4.2 现代写法script setup语法糖](#4.2 现代写法script setup语法糖)
[4.3 script setup的优势](#4.3 script setup的优势)
[Q1:Vue2 和 Vue3 的区别有哪些?](#Q1:Vue2 和 Vue3 的区别有哪些?)
[Q2:setup 提供了什么?](#Q2:setup 提供了什么?)
[Q3:script setup和普通 script有什么区别?](#Q3:script setup和普通 script有什么区别?)
一、核心区别速览
| 对比维度 | Vue2 | Vue3 |
|---|---|---|
| 响应式原理 | Object.defineProperty |
Proxy |
| API 风格 | Options API(选项式) | Composition API(组合式) |
| 生命周期 | beforeCreate、created... | setup 代替前两个,其他加 on |
| 性能 | 一般 | 更快、更小 |
| TypeScript | 支持较弱 | 原生支持 |
| 根实例创建 | new Vue() |
createApp() |
| 多根节点 | ❌ 不支持 | ✅ 支持(Fragment) |
| Teleport | ❌ 无 | ✅ 有 |
| Suspense | ❌ 无 | ✅ 有 |
二、详细对比
1. 响应式原理不同(最重要)
Vue2:Object.defineProperty
javascript
// Vue2 响应式原理(简化)
Object.defineProperty(obj, 'name', {
get() { /* 收集依赖 */ },
set() { /* 触发更新 */ }
})
// 问题1:新增属性监听不到
this.user.newProp = 'hello' // ❌ 不响应,需要 $set
this.$set(this.user, 'newProp', 'hello') // ✅ 需要额外 API
// 问题2:删除属性监听不到
delete this.user.name // ❌ 不响应,需要 $delete
// 问题3:数组下标修改监听不到
this.list[0] = newValue // ❌ 不响应
Vue3:Proxy
javascript
// Vue3 响应式原理(简化)
const proxy = new Proxy(obj, {
get(target, key) { /* 收集依赖 */ },
set(target, key, value) { /* 触发更新 */ },
deleteProperty(target, key) { /* 触发更新 */ }
})
// ✅ 新增属性自动响应
state.user.newProp = 'hello' // ✅ 自动响应
// ✅ 删除属性自动响应
delete state.user.name // ✅ 自动响应
// ✅ 数组下标自动响应
state.list[0] = newValue // ✅ 自动响应
// 不需要 $set、$delete
2. 写法不同(最明显)
Vue2:Options API
javascript
<script>
export default {
data() {
return {
count: 0,
user: null
}
},
computed: {
double() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
this.fetchUser()
}
}
</script>
Vue3:Composition API
javascript
<script setup>
import { ref, computed, onMounted } from 'vue'
// 计数器逻辑(聚在一起)
const count = ref(0)
const double = computed(() => count.value * 2)
const increment = () => count.value++
// 用户逻辑(聚在一起)
const user = ref(null)
const fetchUser = async () => {
user.value = await api.getUser()
}
onMounted(() => {
fetchUser()
})
</script>
3. 生命周期变化
| Vue2 | Vue3 (Options API) | Vue3 (Composition API) |
|---|---|---|
beforeCreate |
beforeCreate |
❌ 不需要(setup 替代) |
created |
created |
❌ 不需要(setup 替代) |
beforeMount |
beforeMount |
onBeforeMount |
mounted |
mounted |
onMounted |
beforeUpdate |
beforeUpdate |
onBeforeUpdate |
updated |
updated |
onUpdated |
beforeDestroy |
beforeUnmount |
onBeforeUnmount |
destroyed |
unmounted |
onUnmounted |
4. 性能提升
| 优化点 | 说明 |
|---|---|
| Tree shaking | 未使用的代码不打包,体积更小 |
| Diff 算法优化 | 增加静态标记,只对比动态内容 |
| 静态节点提升 | 静态节点只创建一次,复用 |
| 事件缓存 | 事件处理函数缓存,减少内存开销 |
5. 其他重要区别
5.1 多根节点(Fragment)
javascript
<!-- Vue2:必须只有一个根节点 -->
<template>
<div> <!-- 必须有一个包裹元素 -->
<h1>标题</h1>
<p>内容</p>
</div>
</template>
<!-- Vue3:支持多个根节点 -->
<template>
<h1>标题</h1>
<p>内容</p>
</template>
5.2 Teleport(传送门)
javascript
<!-- 弹窗挂载到 body,避免被父组件样式影响 -->
<template>
<teleport to="body">
<div class="modal">
<h3>弹窗标题</h3>
<p>弹窗内容</p>
</div>
</teleport>
</template>
5.3 Suspense(异步组件)
javascript
<template>
<Suspense>
<template #default>
<AsyncComponent /> <!-- 异步组件 -->
</template>
<template #fallback>
<div>加载中...</div> <!-- 加载时显示 -->
</template>
</Suspense>
</template>
5.4 根实例创建方式
javascript
// Vue2
import Vue from 'vue'
import App from './App.vue'
const vm = new Vue({
render: h => h(App)
}).$mount('#app')
// Vue3
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
5.5 移除的 API
| 移除项 | 替代方案 |
|---|---|
$on、$off |
mitt、事件总线 |
$set、$delete |
不需要了(Proxy 自动响应) |
| 过滤器 | 计算属性或方法 |
$children |
使用 $refs |
三、setup 提供的核心优势
| 优势 | 说明 |
|---|---|
| 按功能组织代码 | 相关逻辑放在一起,而不是分散在 data、methods、mounted |
| 逻辑复用 | 可以封装成自定义 Hooks,在多个组件间复用 |
| TypeScript 友好 | 类型推导完美,不需要额外类型声明 |
| 更好的性能 | 编译时优化,减少运行时开销 |
| 没有 this 困扰 | 普通函数中用变量,不用担心 this 指向 |
| Tree-shaking 支持 | 未使用的 API 不会打包 |
四、setup 怎么用?
4.1 传统写法(setup 函数)
javascript
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
// 必须 return,才能在模板中使用
return { count, increment }
}
}
</script>
4.2 现代写法script setup语法糖
(<script setup> 语法糖)
javascript
<script setup>
import { ref } from 'vue'
// 直接写,不需要 return
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
4.3 script setup的优势
| 优势 | 说明 |
|---|---|
| 代码更少 | 不需要 export default 和 return |
| 自动暴露 | 定义的变量、函数自动在模板可用 |
| 更好的性能 | 编译时优化 |
| 更好的 TS 支持 | 类型推导更准确 |
五、面试高频问题
Q1:Vue2 和 Vue3 的区别有哪些?
答:
响应式原理 :Vue2 用
Object.defineProperty,Vue3 用Proxy(能监听新增、删除、数组)API 风格 :Vue2 是 Options API,Vue3 是 Composition API(
<script setup>)生命周期 :Vue3 用
setup代替beforeCreate/created,其他加on前缀性能:Vue3 打包更小、渲染更快
新特性:Vue3 支持多根节点、Teleport、Suspense
TypeScript:Vue3 原生支持更好
根实例 :Vue2 用
new Vue(),Vue3 用createApp()
Q2:setup 提供了什么?
答:
setup是 Vue3 组合式 API 的入口,提供了以下核心能力:
响应式 API :
ref、reactive计算属性 :
computed侦听器 :
watch、watchEffect生命周期 :
onMounted、onUpdated、onUnmounted等组件通信 :
defineProps、defineEmits、defineExpose依赖注入 :
provide、inject模板引用 :
ref核心优势:代码按功能组织、逻辑复用方便、TypeScript 友好、没有 this 困扰、性能更好。
Q3: script setup和普通 script有什么区别?
答:
<script setup>是语法糖,代码更简洁,不需要return定义的变量、函数自动在模板中可用
更好的性能(编译时优化)和 TypeScript 支持
是 Vue 3 推荐写法