距离 Vue 3 发布"默认版本"已经过去很久了,但不少开发者在从 Vue 2 迁移或新项目起步时,仍希望有一份清晰的知识点地图,快速掌握 Vue 3 到底改了哪些、新增了什么、怎么用得顺手。这篇文章就为你整理 Vue 3 的关键知识点,覆盖组合式 API、响应式系统、新组件、新指令和生态变化,配合代码示例,让你一篇读透。
- 应用创建方式变了
Vue 3 不再使用 new Vue(),而是通过 createApp 创建应用实例:
javascript
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
全局 API 也挂载到应用实例上,比如 app.component()、app.directive()、app.use() 等,这使得多个 Vue 应用之间不再互相污染。
- 组合式 API 核心
2.1 setup 函数
setup 是组合式 API 的入口,在组件创建之前执行,接收 props 和 context。
javascript
export default {
setup(props, { attrs, slots, emit, expose }) {
console.log(props.title)
return { /* 暴露给模板的数据和方法 */ }
}
}
2.2
它简化了 setup() 的书写,无需手动 return,且默认将顶层绑定暴露给模板。
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
这是目前最推荐的写法,能配合 TypeScript 带来极佳体验。
- 响应式系统:ref 与 reactive
3.1 ref
用于定义基本类型或对象类型的响应式数据,访问值需通过 .value。
javascript
const name = ref('Vue')
const obj = ref({ x: 1 })
在模板中会自动解包,直接写 {{ name }} 即可。
3.2 reactive
用于定义对象类型的响应式数据,直接访问属性,无需 .value。
javascript
const state = reactive({ count: 0 })
state.count++
注意:reactive 不可直接重新赋值(会失去响应式),且解构后响应式丢失。通常搭配 toRefs 或转向 ref 管理整个对象。
3.3 toRef 与 toRefs
用于从 reactive 对象中解构出保持响应式的引用:
javascript
const state = reactive({ name: 'Vue', version: 3 })
const { name, version } = toRefs(state)
// 此时 name 是一个 Ref<string>
- computed 与 watch 的进化
4.1 computed
接收 getter 函数,返回只读的 ref 对象;也可以传入带 get/set 的对象。
javascript
const double = computed(() => count.value * 2)
4.2 watch 与 watchEffect
· watch:需要明确指定监听源,支持惰性执行、获取旧值。 · watchEffect:自动追踪回调中的响应式依赖,立即执行一次。
javascript
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变为 ${newVal}`)
})
watchEffect(() => {
console.log(`当前 count 是 ${count.value}`)
})
新变化:watch 现在可以监听多个源、支持深度监听配置 { deep: true }(默认浅层),并且可以终止监听(通过返回的 stop 函数)。
- 生命周期钩子改名
Vue 3 的选项式 API 中,beforeDestroy → beforeUnmount,destroyed → unmounted。组合式 API 中对应:
Vue 2 选项 Vue 3 组合式 API beforeCreate 直接写在 setup 中 created 直接写在 setup 中 beforeMount onBeforeMount mounted onMounted beforeUpdate onBeforeUpdate updated onUpdated beforeUnmount onBeforeUnmount unmounted onUnmounted
所有钩子均需从 vue 中导入,并且在 setup 中同步调用。
- 组件通信新写法
6.1 defineProps 与 defineEmits
在
vue
<script setup>
const props = defineProps({
title: String,
likes: { type: Number, default: 0 }
})
const emit = defineEmits(['update', 'delete'])
emit('update', 1)
</script>
6.2 多 v-model
Vue 3 支持在同一个组件上使用多个 v-model:
vue
<!-- 父组件 -->
<Child v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 子组件 -->
<script setup>
defineProps(['title', 'content'])
defineEmits(['update:title', 'update:content'])
</script>
6.3 provide 与 inject
用于跨层级组件通信,在组合式 API 中可直接使用:
javascript
// 祖先组件
provide('key', reactiveData)
// 后代组件
const data = inject('key')
- 模板新特性
7.1 Fragments(片段)
组件模板支持多个根节点,不再需要唯一根元素包裹:
vue
<template>
<header>...</header>
<main>...</main>
<footer>...</footer>
</template>
7.2 Teleport(传送门)
允许将模板的一部分"传送"到 DOM 中任意位置,常用于模态框、通知等。
vue
<Teleport to="body">
<div class="modal">...</div>
</Teleport>
7.3 Suspense(实验性)
用于协调异步组件加载,提供 #default 和 #fallback 两个插槽:
vue
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<Loading />
</template>
</Suspense>
虽然稳定,但在生产级项目中使用需考虑 SSR 兼容性。
- 新的指令和变化
· v-memo:性能优化指令,用于有条件地跳过子树更新。
html
<div v-memo="[valueA, valueB]">...</div>
· v-bind 合并行为:现在 v-bind="object" 和单独的属性合并时,同一个属性会按声明顺序覆盖,更符合直觉。 · v-for 和 v-if 优先级改变:在 Vue 3 中,v-if 优先级高于 v-for,Vue 2 反之。官方推荐不要在同一元素上同时使用两者,改用