1. Vue 3 的响应式系统升级
Vue 3 最核心的改进之一就是彻底重构了响应式系统。与 Vue 2 基于 Object.defineProperty 的实现不同,Vue 3 采用了 ES6 的 Proxy 特性来实现响应式。这个改变带来了几个显著优势:
- 性能提升:Proxy 是浏览器原生支持的 API,不需要像 Vue 2 那样递归遍历对象的所有属性进行劫持
- 数组变化检测:Vue 2 中需要通过重写数组方法来实现响应式,而 Vue 3 可以直接检测数组索引变化
- 更丰富的响应式操作:可以检测属性的添加和删除,支持 Map、Set 等集合类型
1.1 响应式 API 的变化
Vue 3 提供了几个新的响应式 API:
javascript复制import { reactive, ref, computed } from 'vue'
// 创建响应式对象
const state = reactive({
count: 0
})
// 创建响应式基本类型值
const count = ref(0)
// 计算属性
const doubleCount = computed(() => count.value * 2)
注意:reactive() 只能用于对象,基本类型值需要使用 ref()。ref 通过 .value 属性访问实际值,但在模板中会自动解包。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Composition API 深度解析
Composition API 是 Vue 3 引入的最重要特性之一,它解决了 Options API 在复杂组件中的几个痛点:
- 逻辑复用困难:Options API 中相关逻辑分散在各个选项中
- 类型推断困难:Options API 对 TypeScript 支持不够友好
- 代码组织问题:大型组件中代码难以维护
2.1 setup 函数的使用
setup 函数是 Composition API 的入口点,它在组件创建之前执行:
javascript复制import { ref, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
count.value++
}
onMounted(() => {
console.log('组件已挂载')
})
return {
count,
increment
}
}
}
2.2 逻辑复用模式
Composition API 使得逻辑复用变得非常简单,我们可以将相关逻辑提取为组合式函数:
javascript复制// useCounter.js
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return {
count,
increment,
decrement
}
}
// 在组件中使用
import { useCounter } from './useCounter'
export default {
setup() {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
3. Teleport 组件的妙用
Teleport 是 Vue 3 新增的内置组件,它可以将子组件渲染到 DOM 树的其他位置,非常适合处理模态框、通知、弹出菜单等需要突破组件层级限制的场景。
3.1 基本用法
html复制<template>
<button @click="showModal = true">打开模态框</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<p>这是一个模态框</p>
<button @click="showModal = false">关闭</button>
</div>
</Teleport>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const showModal = ref(false)
return {
showModal
}
}
}
</script>
3.2 实际应用场景
- 全局通知系统:将通知渲染到页面顶部的固定位置
- 全屏模态框:避免被父组件的 overflow:hidden 影响
- 工具提示:确保提示不会被父元素的 z-index 或 overflow 属性裁剪
提示:Teleport 的 to 属性可以是有效的 CSS 选择器,如 "#some-id"、".some-class" 或 "body"
4. Fragment 和多个根节点
Vue 2 中每个组件必须有且只有一个根节点,这在某些场景下会导致不必要的包装 div。Vue 3 取消了这一限制,支持多根节点组件。
4.1 多根节点组件
html复制<template>
<header>...</header>
<main>...</main>
<footer>...</footer>
</template>
4.2 注意事项
- 属性继承:在多根节点组件中,非 prop 的属性不会自动继承,需要显式绑定
- 过渡动画:transition 组件仍然需要单个子元素
- TypeScript:多根节点组件可能需要额外的类型声明
5. 性能优化技巧
Vue 3 在性能方面做了大量改进,但正确的使用方式仍然很重要。以下是几个实用的性能优化技巧:
5.1 v-memo 指令
v-memo 是 Vue 3.2 新增的指令,它可以缓存模板的子树,在依赖没有变化时跳过更新:
html复制<div v-memo="[valueA, valueB]">
<!-- 这部分只会在 valueA 或 valueB 变化时重新渲染 -->
{{ valueA }} {{ valueB }}
</div>
5.2 静态提升
Vue 3 的编译器会自动提升静态节点,但我们可以通过以下方式进一步优化:
- 将不变化的组件标记为静态
- 合理使用 v-once 指令
- 避免在模板中使用复杂表达式
5.3 组件懒加载
结合 Suspense 使用动态导入实现组件懒加载:
javascript复制import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
6. TypeScript 支持增强
Vue 3 从一开始就考虑了 TypeScript 支持,提供了更好的类型推断和开发体验。
6.1 组件类型定义
使用 defineComponent 定义组件可以获得完整的类型支持:
typescript复制import { defineComponent } from 'vue'
export default defineComponent({
props: {
message: {
type: String,
required: true
}
},
setup(props) {
// props 有正确的类型推断
console.log(props.message)
}
})
6.2 组合式函数类型
为组合式函数添加类型注解:
typescript复制import { ref, Ref } from 'vue'
interface CounterOptions {
initialValue?: number
}
export function useCounter(options: CounterOptions = {}): {
count: Ref<number>
increment: () => void
} {
const count = ref(options.initialValue || 0)
function increment() {
count.value++
}
return {
count,
increment
}
}
7. 自定义渲染器 API
Vue 3 将核心逻辑与 DOM 渲染分离,使得创建自定义渲染器成为可能。这意味着 Vue 不仅可以渲染到 DOM,还可以渲染到:
- 移动端原生组件
- WebGL
- 终端命令行界面
- PDF 文档
7.1 创建简单自定义渲染器
javascript复制import { createRenderer } from 'vue'
const { createApp } = createRenderer({
createElement(type) {
console.log(`创建元素: ${type}`)
return { type }
},
insert(el, parent) {
console.log(`将 ${el.type} 插入到 ${parent.type || '根'}`)
}
})
const app = createApp({
render() {
return h('div', null, 'Hello World')
}
})
app.mount({ type: 'root' })
8. 全局 API 变更
Vue 3 对全局 API 进行了重大调整,主要是为了更好的 Tree Shaking 支持和更清晰的代码组织。
8.1 主要变更点
| Vue 2 全局 API | Vue 3 替代方案 |
|---|---|
| Vue.nextTick | import { nextTick } from 'vue' |
| Vue.set | 直接赋值 (Proxy 自动检测) |
| Vue.delete | 直接删除属性 |
| Vue.filter | 使用全局方法或组件内 filters |
| Vue.directive | app.directive() |
8.2 创建应用实例
Vue 3 引入了 createApp 工厂函数:
javascript复制import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 注册全局组件
app.component('MyComponent', {
/* 组件选项 */
})
// 注册全局指令
app.directive('focus', {
mounted(el) {
el.focus()
}
})
app.mount('#app')
9. 单文件组件改进
Vue 3 对单文件组件(SFC)进行了一些增强,提升了开发体验。
9.1 script setup 语法糖
<script setup> 是编译时语法糖,可以更简洁地使用 Composition API:
html复制<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
9.2 样式特性增强
- 深度选择器:使用
:deep()替代/deep/或>>> - CSS 模块:更完善的 CSS Modules 支持
- 状态驱动的动态 CSS:在
<style>中使用 v-bind
html复制<script setup>
import { ref } from 'vue'
const color = ref('red')
</script>
<template>
<div class="text">Hello</div>
</template>
<style>
.text {
color: v-bind(color);
}
</style>
10. 迁移策略与兼容性
对于已有 Vue 2 项目,Vue 3 提供了渐进式迁移方案。
10.1 兼容性构建
Vue 3 提供了 @vue/compat 构建版本,它提供了与 Vue 2 兼容的行为:
javascript复制import { createApp } from 'vue/dist/vue.esm-bundler.js'
10.2 迁移步骤建议
- 先升级到 Vue 2.7(包含部分 Vue 3 特性)
- 使用迁移构建运行现有代码
- 逐步替换不兼容的特性
- 移除兼容性构建,切换到标准 Vue 3
10.3 常见不兼容点
- 事件 API 变更($on, $off 移除)
- 过滤器移除
- 异步组件定义方式变更
- v-model 语法变更
- 函数式组件语法变更
我在实际项目迁移中发现,最大的挑战不是技术层面的变更,而是团队需要适应新的开发模式和思维方式。特别是从 Options API 转向 Composition API,需要一段时间的适应期。建议新项目直接使用 Vue 3 和 Composition API,而现有大型项目可以采用渐进式迁移策略。
