Vue 3

Vue 3 是 Vue.js 的最新主要版本,带来了全新的 Composition API、更好的性能和 TypeScript 支持。

为什么选择 Vue 3

  • 更小的体积 — 运行时体积比 Vue 2 减少约 30%
  • 更好的性能 — 虚拟 DOM 重写,编译时优化
  • Composition API — 更好的逻辑复用和代码组织
  • 更好的 TypeScript 支持 — 源码使用 TypeScript 重写
  • 更灵活的架构 — 拆分了更多独立模块

核心概念

响应式系统

Vue 3 使用 Proxy 替代了 Vue 2 的 Object.defineProperty:

import { reactive, ref, computed, watch } from 'vue'
 
// ref 用于基本类型
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
 
// reactive 用于对象
const state = reactive({
  name: 'Vue 3',
  version: '3.4+'
})
 
// computed 计算属性
const doubleCount = computed(() => count.value * 2)
 
// watch 监听
watch(count, (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`)
})

组合式 API (Composition API)

组合式 API 允许我们将相关逻辑组织在一起:

import { ref, onMounted, onUnmounted } from 'vue'
 
// 鼠标位置示例
export default {
  setup() {
    const x = ref(0)
    const y = ref(0)
 
    function updatePosition(e) {
      x.value = e.clientX
      y.value = e.clientY
    }
 
    onMounted(() => {
      window.addEventListener('mousemove', updatePosition)
    })
 
    onUnmounted(() => {
      window.removeEventListener('mousemove', updatePosition)
    })
 
    // 返回的值可以在模板中使用
    return { x, y }
  }
}

Script Setup

<script setup> 是使用组合式 API 的简化语法:

<script setup>
import { ref, computed } from 'vue'
 
const props = defineProps({
  title: String
})
 
const emit = defineEmits(['update', 'delete'])
 
// 响应式状态
const count = ref(0)
 
// 计算属性
const doubled = computed(() => count.value * 2)
 
// 方法
function increment() {
  count.value++
  emit('update', count.value)
}
 
// 可以直接返回函数
defineExpose({ count, increment })
</script>
 
<template>
  <div>
    <h1>{{ props.title }}</h1>
    <p>Count: {{ count }}</p>
    <p>Doubled: {{ doubled }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

生命周期钩子

Vue 2Vue 3 Composition API
createdsetup()
mountedonMounted
updatedonUpdated
destroyedonUnmounted
beforeCreate-
beforeMountonBeforeMount
beforeUpdateonBeforeUpdate
beforeUnmountonBeforeUnmount

依赖注入

使用 provideinject 实现跨组件通信:

// 父组件
import { provide, ref } from 'vue'
 
export default {
  setup() {
    const theme = ref('dark')
    provide('theme', theme)
  }
}
 
// 子组件
import { inject } from 'vue'
 
export default {
  setup() {
    const theme = inject('theme')
    return { theme }
  }
}

Teleport

Teleport 可以将组件渲染到 DOM 树的任意位置:

<teleport to="body">
  <div v-if="isModalOpen" class="modal">
    <h2>Modal Content</h2>
    <button @click="$emit('close')">Close</button>
  </div>
</teleport>

Suspense

Suspense 用于处理异步组件加载状态:

<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>

与 Vue 2 的主要区别

特性Vue 2Vue 3
响应式原理Object.definePropertyProxy
组件类型单文件组件单文件组件 + Fragments
API 风格Options APIComposition API + Options API
全局 APIVue.set/delete需要使用 ES 模块
过滤器支持不推荐,使用 methods 替代
异步组件callback 方式Promise + Suspense

常见问题

如何迁移 Vue 2 项目?

推荐使用 vue-migration-helper 工具辅助迁移:

npm install -g vue-migration-helper
vue-migration-helper src/

ref 和 reactive 如何选择?

  • ref:用于基本类型和需要 .value 访问的值
  • reactive:用于对象和数组,更直观的响应式

watch 和 watchEffect 的区别?

  • watch:显式指定要监听的数据,只有数据变化时才执行
  • watchEffect:自动收集依赖,依赖变化时立即执行

相关资源