已掌握 Vue2 的开发者,快速上手 Vue3
-
- [一、最核心变化:从 Options API 到 Composition API](#一、最核心变化:从 Options API 到 Composition API)
-
- [1.1 入口函数:`setup()`](#1.1 入口函数:
setup()
) - [1.2 响应式 API:替代 Vue2 的 `data`](#1.2 响应式 API:替代 Vue2 的
data
) - [1.3 计算属性与监听:`computed`/`watch`](#1.3 计算属性与监听:
computed
/watch
) -
- [(1)计算属性 `computed`](#(1)计算属性
computed
) - [(2)监听器 `watch`](#(2)监听器
watch
)
- [(1)计算属性 `computed`](#(1)计算属性
- [1.1 入口函数:`setup()`](#1.1 入口函数:
- 二、生命周期钩子的变化
- [三、模板语法的 2 个关键变化](#三、模板语法的 2 个关键变化)
-
- [3.1 多根节点(Fragment)](#3.1 多根节点(Fragment))
- [3.2 `v-model` 统一(替代 `sync` 修饰符)](#3.2
v-model
统一(替代sync
修饰符))
- [四、全局 API 的变化(`createApp`)](#四、全局 API 的变化(
createApp
)) -
-
- [实战示例:main.js 入口文件](#实战示例:main.js 入口文件)
-
- 五、必学新增特性(提升开发效率)
-
- [5.1 异步组件:`defineAsyncComponent`](#5.1 异步组件:
defineAsyncComponent
) - [5.2 传送门:`Teleport`(解决样式嵌套问题)](#5.2 传送门:
Teleport
(解决样式嵌套问题))
- [5.1 异步组件:`defineAsyncComponent`](#5.1 异步组件:
- 六、快速上手步骤总结
对于已掌握 Vue2 的开发者,快速上手 Vue3 的核心是 聚焦「差异点」和「新增核心特性」,无需重复学习基础概念(如组件、指令、路由联动等)。以下是按「优先级+实用性」排序的核心知识点,附带 Vue2 对比和实战代码示例:
一、最核心变化:从 Options API 到 Composition API
Vue2 用 Options API (data、methods、computed 等选项)组织代码,逻辑分散在不同选项中;Vue3 新增的 Composition API (基于 setup
函数)允许按「业务逻辑」聚合代码,更适合复杂组件。
1.1 入口函数:setup()
setup
是 Composition API 的「入口」,替代了 Vue2 中 data
、created
、beforeCreate
的核心功能:
- 执行时机 :组件实例创建前(
beforeCreate
之前),因此setup
内 没有this
(直接用this
会报错)。 - 返回值 :返回的对象会暴露给模板(类似 Vue2 的
data
+methods
)。
1.2 响应式 API:替代 Vue2 的 data
Vue2 靠 Object.defineProperty
实现响应式,有「数组索引修改不响应」「对象新增属性不响应」的痛点;Vue3 用 Proxy
重写响应式,并用 ref
/reactive
两个 API 声明响应式数据,彻底解决痛点。
场景 | Vue2 写法 | Vue3 写法 | 关键说明 |
---|---|---|---|
基本类型(数字/字符串) | data() { return { num: 0 } } |
const num = ref(0) |
ref 用于「基本类型」,访问时需加 .value (模板中不用加) |
引用类型(对象/数组) | data() { return { obj: { name: 'a' } } } |
const obj = reactive({ name: 'a' }) |
reactive 用于「引用类型」,直接访问属性(无需 .value ) |
实战示例:响应式数据+方法
vue
<!-- Vue3 组件 -->
<template>
<div>
<p>基本类型:{{ num }}</p>
<p>引用类型:{{ obj.name }}</p>
<button @click="addNum">加1</button>
<button @click="changeName">改名字</button>
</div>
</template>
<script setup>
// 1. 按需引入响应式 API(Vue3 推荐「树摇」,减少打包体积)
import { ref, reactive } from 'vue'
// 2. 声明响应式数据
const num = ref(0) // 基本类型用 ref
const obj = reactive({ name: 'Vue2' }) // 引用类型用 reactive
// 3. 声明方法(直接写函数,无需嵌套在 methods 中)
const addNum = () => {
num.value += 1 // ref 类型在 JS 中需加 .value
}
const changeName = () => {
obj.name = 'Vue3' // reactive 类型直接修改属性
}
</script>
1.3 计算属性与监听:computed
/watch
替代 Vue2 的 computed
和 watch
选项,用法更灵活(可在 setup
内随时声明)。
(1)计算属性 computed
vue
<script setup>
import { ref, computed } from 'vue'
const num = ref(0)
// 只读计算属性(默认)
const doubleNum = computed(() => num.value * 2)
// 可写计算属性(需传对象)
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val) => {
const [f, l] = val.split(' ')
firstName.value = f
lastName.value = l
}
})
</script>
(2)监听器 watch
支持监听单个/多个响应式数据,功能比 Vue2 更强大:
vue
<script setup>
import { ref, reactive, watch } from 'vue'
const num = ref(0)
const obj = reactive({ name: 'a', age: 18 })
// 1. 监听 ref 数据
watch(num, (newVal, oldVal) => {
console.log('num变了:', newVal, oldVal)
})
// 2. 监听 reactive 数据的单个属性(需用函数返回)
watch(() => obj.name, (newName) => {
console.log('名字变了:', newName)
})
// 3. 监听多个数据(数组形式)
watch([num, () => obj.age], ([newNum, newAge], [oldNum, oldAge]) => {
console.log('num或age变了', newNum, newAge)
})
</script>
二、生命周期钩子的变化
Vue3 保留了 Vue2 的生命周期逻辑,但 钩子函数需按需引入 ,且部分名称有调整(去掉 before
/after
,统一用 onXxx
)。
Vue2 生命周期 | Vue3 对应钩子(需引入) | 说明 |
---|---|---|
beforeCreate |
无(直接用 setup ) |
setup 执行时机更早 |
created |
无(直接用 setup ) |
同上 |
beforeMount |
onBeforeMount |
组件挂载前 |
mounted |
onMounted |
组件挂载后(常用) |
beforeUpdate |
onBeforeUpdate |
数据更新前 |
updated |
onUpdated |
数据更新后 |
beforeDestroy |
onBeforeUnmount |
组件卸载前(名称调整) |
destroyed |
onUnmounted |
组件卸载后(常用,名称调整) |
实战示例:组件挂载后请求数据
vue
<script setup>
import { onMounted } from 'vue'
import axios from 'axios'
// 组件挂载后请求数据(替代 Vue2 的 mounted 选项)
onMounted(async () => {
const res = await axios.get('/api/data')
console.log('请求结果:', res.data)
})
</script>
三、模板语法的 2 个关键变化
Vue3 模板支持更多灵活写法,核心变化集中在「多根节点」和「v-model 统一」。
3.1 多根节点(Fragment)
Vue2 模板 必须有一个根节点 (否则报错);Vue3 支持「多根节点」,无需外层包裹 div
:
vue
<!-- Vue3 合法模板(无需根节点) -->
<template>
<p>第一个节点</p>
<p>第二个节点</p>
</template>
3.2 v-model
统一(替代 sync
修饰符)
Vue2 中,v-model
是 value
+input
事件的语法糖,sync
是 update:prop
事件的语法糖,两者需区分;Vue3 统一了 v-model
,直接通过「参数」绑定任意属性,彻底替代 sync
。
场景 | Vue2 写法 | Vue3 写法 |
---|---|---|
基础双向绑定 | <Child v-model="num" /> |
<Child v-model="num" /> |
自定义属性绑定(sync) | <Child :title.sync="title" /> |
<Child v-model:title="title" /> |
实战示例:自定义输入框组件
vue
<!-- 父组件 -->
<template>
<CustomInput
v-model="num" <!-- 基础绑定(默认绑定 value 属性) -->
v-model:title="title" <!-- 自定义绑定(绑定 title 属性) -->
/>
</template>
<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'
const num = ref(0)
const title = ref('Vue3')
</script>
<!-- 子组件 CustomInput.vue -->
<template>
<input
:value="modelValue" <!-- 基础绑定的默认属性名:modelValue(替代 Vue2 的 value) -->
@input="$emit('update:modelValue', $event.target.value)" <!-- 触发更新 -->
:value="title" <!-- 自定义绑定的属性名:title -->
@input="$emit('update:title', $event.target.value)" <!-- 触发更新 -->
/>
</template>
<script setup>
// 子组件需声明接收的属性(替代 Vue2 的 props 选项)
defineProps(['modelValue', 'title'])
// 子组件需声明可触发的事件(可选,用于类型提示)
defineEmits(['update:modelValue', 'update:title'])
</script>
四、全局 API 的变化(createApp
)
Vue2 用 new Vue()
创建全局实例,Vue3 用 createApp
替代,避免全局污染,用法更严谨。
操作 | Vue2 写法 | Vue3 写法 |
---|---|---|
创建全局实例 | new Vue({ el: '#app', render: h => h(App) }) |
createApp(App).mount('#app') |
全局挂载组件 | Vue.component('MyBtn', MyBtn) |
app.component('MyBtn', MyBtn) |
全局挂载指令 | Vue.directive('focus', { ... }) |
app.directive('focus', { ... }) |
实战示例:main.js 入口文件
javascript
// Vue2 main.js
import Vue from 'vue'
import App from './App.vue'
Vue.component('MyBtn', MyBtn) // 全局组件
new Vue({ render: h => h(App) }).$mount('#app')
// Vue3 main.js(推荐用 <script setup>,但入口文件需显式创建 app)
import { createApp } from 'vue'
import App from './App.vue'
import MyBtn from './MyBtn.vue'
// 1. 创建 app 实例
const app = createApp(App)
// 2. 全局配置(组件、指令、原型链等)
app.component('MyBtn', MyBtn) // 全局组件
// 3. 挂载到 DOM
app.mount('#app')
五、必学新增特性(提升开发效率)
5.1 异步组件:defineAsyncComponent
Vue2 异步组件需用 () => import()
,Vue3 用 defineAsyncComponent
封装,支持更灵活的加载逻辑(如加载失败、加载中状态):
vue
<script setup>
import { defineAsyncComponent } from 'vue'
// 1. 基础异步组件(替代 Vue2 的 () => import('./Child.vue'))
const Child = defineAsyncComponent(() => import('./Child.vue'))
// 2. 带加载状态的异步组件
const AsyncChild = defineAsyncComponent({
loader: () => import('./AsyncChild.vue'),
loadingComponent: Loading, // 加载中显示的组件
errorComponent: Error, // 加载失败显示的组件
delay: 200, // 延迟 200ms 后显示加载组件(避免闪烁)
})
</script>
5.2 传送门:Teleport
(解决样式嵌套问题)
Teleport
允许将组件的 DOM 渲染到任意位置(如 body
下),避免被父组件样式(如 overflow: hidden
)影响,常用於模态框、弹窗。
vue
<template>
<button @click="showModal = true">打开弹窗</button>
<!-- Teleport:将内容渲染到 body 下 -->
<Teleport to="body">
<div class="modal" v-if="showModal">
<p>弹窗内容(渲染在 body 下,不受父组件样式影响)</p>
<button @click="showModal = false">关闭</button>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>
六、快速上手步骤总结
- 放弃
this
:用setup
作为入口,数据用ref
/reactive
声明,方法直接写函数。 - 替换生命周期 :按需求引入
onMounted
/onUnmounted
等钩子,替代 Vue2 的选项。 - 统一
v-model
:用v-model:prop
替代sync
,子组件通过update:prop
触发更新。 - 调整全局 API :入口文件用
createApp
创建实例,全局组件/指令用app.xxx
挂载。 - 按需用新特性 :异步组件用
defineAsyncComponent
,弹窗用Teleport
。
通过以上知识点,你可以直接将 Vue2 项目的核心逻辑迁移到 Vue3,剩余细节(如 provide/inject
增强、script setup
语法糖进阶)可在实战中逐步补充。