---
url: /vue/vue3-summary.md
---
# Vue 3 全面总结

## 目录

1. [响应式系统](#1-响应式系统)
2. [组合式 API (Composition API)](#2-组合式-api-composition-api)
3. [生命周期钩子](#3-生命周期钩子)
4. [核心内置组件](#4-核心内置组件)
5. [自定义指令](#5-自定义指令)
6. [依赖注入](#6-依赖注入)
7. [渲染函数与虚拟 DOM](#7-渲染函数与虚拟-dom)
8. [高级响应式工具](#8-高级响应式工具)
9. [服务端渲染 (SSR)](#9-服务端渲染-ssr)
10. [底层原理](#10-底层原理)

***

## 1. 响应式系统

### 1.1 ref - 基础引用

`ref()` 用于创建响应式引用，可包含任何类型的值。

```javascript
import { ref } from 'vue'

// 原始值
const count = ref(0)
const message = ref('Hello')

// 访问和修改需要通过 .value
count.value++
console.log(count.value) // 1

// 对象类型（仍然是浅响应）
const user = ref({ name: 'John', age: 30 })
user.value.age = 31

// 模板中自动解包，不需要 .value
// <div>{{ count }}</div>
```

### 1.2 reactive - 深度响应式对象

`reactive()` 创建一个深度响应式的对象代理。

```javascript
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: {
    name: 'John',
    profile: { age: 30 }
  }
})

// 直接访问，不需要 .value
state.count++
state.user.profile.age = 31

// 深度响应式 - 嵌套对象也会变成响应式
```

**重要注意事项：**

```javascript
// ❌ 解构会丢失响应性
const { count } = state // count 不再是响应式的

// ✅ 使用 toRefs 保持响应性
import { toRefs } from 'vue'
const { count, user } = toRefs(state) // 保持响应连接
```

### 1.3 computed - 计算属性

创建缓存的、派生的响应式值。

```javascript
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

// 只读计算属性（自动缓存）
const fullName = computed(() => {
  console.log('Computing...') // 只在依赖变化时执行
  return `${firstName.value} ${lastName.value}`
})

console.log(fullName.value) // "John Doe"
console.log(fullName.value) // 缓存，不重新计算

firstName.value = 'Jane'
console.log(fullName.value) // "Jane Doe" - 重新计算

// 可写计算属性
const fullNameWritable = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(newValue) {
    const [first, last] = newValue.split(' ')
    firstName.value = first
    lastName.value = last || ''
  }
})

fullNameWritable.value = 'Alice Smith'
```

### 1.4 watch 与 watchEffect

#### watch - 精确监听

```javascript
import { ref, watch } from 'vue'

const count = ref(0)

// 监听单个 ref
watch(count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldValue} to ${newValue}`)
})

// 监听多个源
const name = ref('John')
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
  console.log('Multiple sources changed')
})

// 监听计算属性或 getter
watch(
  () => count.value * 2,
  (newValue, oldValue) => {
    console.log('Derived value changed')
  }
)

// 选项配置
watch(count, (newValue, oldValue) => {
  console.log('Changed')
}, {
  immediate: true,      // 立即执行回调
  deep: true,           // 深度监听对象/数组
  flush: 'post'         // 'pre' | 'post' | 'sync'
})
```

#### watchEffect - 自动追踪依赖

```javascript
import { ref, watchEffect } from 'vue'

const count = ref(0)

// 立即执行并自动追踪所有访问的响应式数据
const stop = watchEffect((onCleanup) => {
  console.log(`Count is: ${count.value}`)
  
  // 清理函数
  onCleanup(() => {
    console.log('Effect cleanup')
  })
})

count.value++ // 自动触发

// 停止监听
stop()
```

**watch vs watchEffect 对比：**

| 特性 | watch | watchEffect |
|------|-------|-------------|
| 依赖追踪 | 显式指定 | 自动追踪 |
| 初始执行 | 需要 immediate | 立即执行 |
| 接收旧值 | 是 | 否 |
| 性能控制 | 更精确 | 可能追踪多余依赖 |

***

## 2. 组合式 API (Composition API)

### 2.1 setup 函数

```javascript
import { defineComponent, ref } from 'vue'

export default defineComponent({
  props: {
    title: String,
    count: {
      type: Number,
      default: 0
    }
  },
  emits: ['increment', 'decrement'],
  
  setup(props, context) {
    // props 是只读的响应式对象
    console.log(props.title)
    
    // context 包含：attrs, slots, emit
    const { emit, slots, attrs } = context
    
    // 暴露给模板
    return {
      message: ref('Hello'),
      increment() {
        emit('increment')
      }
    }
  }
})
```

### 2.2 script setup 语法糖

推荐使用的简洁语法：

```vue
<script setup>
import { ref, computed, watch } from 'vue'

// Props - 声明式
defineProps({
  title: String,
  count: {
    type: Number,
    default: 0
  }
})

// Props - 类型化（需 TypeScript）
// defineProps<{ title: string; count?: number }>()

// Emits
defineEmits(['increment', 'decrement'])

// 所有顶层变量自动暴露给模板
const message = ref('Hello')
const double = computed(() => props.count * 2)

// 方法
function handleClick() {
  console.log('Clicked')
}

// 模板插槽
const slots = defineSlots()

// 具名插槽暴露
defineOptions({
  name: 'MyComponent'
})
</script>

<template>
  <div @click="handleClick">
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
    <p>{{ double }}</p>
  </div>
</template>
```

### 2.3 Composables (组合函数)

可复用的组合式逻辑：

```javascript
// useCounter.js
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  const double = computed(() => count.value * 2)
  
  const increment = () => count.value++
  const decrement = () => count.value--
  const reset = () => count.value = initialValue
  
  return {
    count,
    double,
    increment,
    decrement,
    reset
  }
}

// 在组件中使用
<script setup>
import { useCounter } from './useCounter'

const { count, double, increment, decrement } = useCounter(10)
</script>
```

***

## 3. 生命周期钩子

### 3.1 Composition API 生命周期

```javascript
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onActivated,
  onDeactivated
} from 'vue'

export default {
  setup() {
    const count = ref(0)
    
    // beforeCreate - setup 之前，无法访问
    // created - setup 函数本身相当于 created
    
    onBeforeMount(() => {
      console.log('挂载前 - DOM 尚未准备')
    })
    
    onMounted(() => {
      console.log('已挂载 - DOM 就绪')
      // 可以安全访问 DOM
    })
    
    onBeforeUpdate(() => {
      console.log('更新前 - 状态已变，DOM 未更新')
    })
    
    onUpdated(() => {
      console.log('已更新 - DOM 反映新状态')
    })
    
    onBeforeUnmount(() => {
      console.log('卸载前 - 清理定时器、监听器')
    })
    
    onUnmounted(() => {
      console.log('已卸载 - 组件从 DOM 移除')
    })
    
    // 错误捕获（捕获子组件错误）
    onErrorCaptured((err, instance, info) => {
      console.error('子组件错误:', err, info)
      return false // 阻止错误向上传播
    })
    
    // KeepAlive 专属
    onActivated(() => {
      console.log('从缓存激活')
    })
    
    onDeactivated(() => {
      console.log('失活到缓存')
    })
    
    return { count }
  }
}
```

### 3.2 生命周期时序图

```
[父 onBeforeMount] → [子 onBeforeMount] → [子 onMounted] → [父 onMounted]
                             ↓
[状态变化] → [onBeforeUpdate] → [DOM 更新] → [onUpdated]
                             ↓
[卸载] → [onBeforeUnmount] → [子卸载] → [onUnmounted]
```

***

## 4. 核心内置组件

### 4.1 Transition - 过渡动画

```vue
<template>
  <!-- 元素显示/隐藏过渡 -->
  <Transition name="fade">
    <div v-if="show">内容</div>
  </Transition>

  <!-- 动态组件过渡 -->
  <Transition name="fade" mode="out-in" appear>
    <component :is="currentView" />
  </Transition>

  <!-- 列表项过渡 -->
  <TransitionGroup tag="ul" name="slide">
    <li v-for="item in items" :key="item.id">
      {{ item.text }}
    </li>
  </TransitionGroup>
</template>

<style>
/* CSS 类名过渡 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 列表过渡 */
.slide-move,
.slide-enter-active,
.slide-leave-active {
  transition: all 0.5s ease;
}

.slide-enter-from {
  opacity: 0;
  transform: translateX(-30px);
}

.slide-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
</style>
```

**Transition Props:**

| Prop | 说明 |
|------|------|
| name | 过渡名称 |
| appear | 初始化时也应用过渡 |
| mode | 模式：in-out | out-in | default |
| css | 是否使用 CSS 过渡 |
| duration | 持续时间 |
| enter-from-class | 进入起始类名 |
| leave-active-class | 离开激活类名 |

### 4.2 Teleport - 传送门

将内容渲染到 DOM 其他位置：

```vue
<template>
  <!-- 传送到 #app 下的 #modal-container -->
  <Teleport to="#modal-container">
    <div class="modal">
      <p>模态框内容</p>
      <button @click="close">关闭</button>
    </div>
  </Teleport>

  <!-- 条件禁用传送 -->
  <Teleport to="#popup" :disabled="displayVideoInline">
    <video src="./movie.mp4" />
  </Teleport>

  <!-- Vue 3.5+ 延迟解析目标 -->
  <Teleport defer to="#late-div">
    内容
  </Teleport>
  
  <!-- 稍后定义的目标 -->
  <div id="late-div"></div>
</template>
```

### 4.3 KeepAlive - 组件缓存

缓存组件实例以保留状态：

```vue
<template>
  <KeepAlive :include="['Home', 'Settings']" :exclude="['About']">
    <component :is="currentComponent" />
  </KeepAlive>
</template>

<script setup>
import { ref } from 'vue'

const currentComponent = ref('Home')
</script>
```

**KeepAlive Props:**

| Prop | 说明 |
|------|------|
| include | 缓存的组件名（字符串/正则/数组） |
| exclude | 不缓存的组件名 |
| max | 最大缓存数量 |

**配合生命周期使用：**

```javascript
import { onActivated, onDeactivated } from 'vue'

onActivated(() => {
  console.log('组件被显示（从缓存恢复）')
  // 重新获取数据等
})

onDeactivated(() => {
  console.log('组件被隐藏（保存到缓存）')
  // 暂停轮询等
})
```

### 4.4 Suspense - 异步依赖

处理异步组件加载：

```vue
<template>
  <Suspense timeout="1000">
    <!-- 默认内容 -->
    <template #default>
      <AsyncComponent />
    </template>
    
    <!-- 加载中回退 -->
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>
```

**Suspense Events:**

```vue
<Suspense 
  @pending="onPending"
  @resolve="onResolve"
  @fallback="onFallback"
>
  <template #default>
    <AsyncComponent />
  </template>
  <template #fallback>
    <div>Loading...</div>
  </template>
</Suspense>
```

***

## 5. 自定义指令

### 5.1 注册方式

```javascript
import { createApp } from 'vue'

const app = createApp({})

// 全局注册
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

// 局部注册
export default {
  directives: {
    focus: {
      mounted(el) {
        el.focus()
      }
    }
  }
}
```

### 5.2 指令钩子

```javascript
const exampleDirective = {
  // 绑定只调用一次
  created(binding, vnode) {
    console.log('指令绑定，元素还未插入')
  },
  
  // 元素插入 DOM
  beforeMount(binding, vnode) {
    console.log('元素插入前')
  },
  
  // 元素插入 DOM 后
  mounted(binding, vnode) {
    console.log('元素已插入')
    // 常用：操作 DOM
  },
  
  // 父组件 VNode 更新前
  beforeUpdate(binding, vnode, prevVnode) {
    console.log('父组件更新前')
  },
  
  // 父组件及其子组件 VNode 都更新后
  updated(binding, vnode, prevVnode) {
    console.log('父组件更新后')
  },
  
  // 元素卸载前
  beforeUnmount(binding, vnode) {
    console.log('元素卸载前')
    // 清理工作
  },
  
  // 元素及子树卸载后
  unmounted(binding, vnode) {
    console.log('元素已卸载')
  }
}
```

### 5.3 binding 对象

```javascript
const myDirective = {
  mounted(el, binding) {
    console.log(binding.name)     // 'my'
    console.log(binding.value)    // 指令值
    console.log(binding.arg)      // 参数，v-el:year 中的 year
    console.log(binding.modifiers) // 修饰符对象 { focus: true }
    console.log(binding.instance)  // ❌ Vue 3 不再提供
  }
}
```

### 5.4 简写形式

```javascript
// 函数形式 - 等价于 mounted 和 updated
app.directive('color', (el, binding) => {
  el.style.color = binding.value
})

// 使用
<div v-color="'red'">红色文本</div>
<div v-color:bg="'blue'">蓝色背景</div>
```

### 5.5 实战示例

```javascript
// 防抖指令
app.directive('debounce', {
  mounted(el, binding) {
    let timer = null
    const handler = (...args) => {
      clearTimeout(timer)
      timer = setTimeout(() => {
        binding.value(...args)
      }, binding.arg || 300)
    }
    el.addEventListener('click', handler)
    
    el._unregister = () => {
      el.removeEventListener('click', handler)
      clearTimeout(timer)
    }
  },
  unmounted(el) {
    el._unregister?.()
  }
})

// 使用
<button v-debounce:500="handleClick">点击</button>
```

***

## 6. 依赖注入

### 6.1 provide / inject 基础

```vue
<!-- 父组件 -->
<script setup>
import { provide, ref, readonly } from 'vue'

const theme = ref('light')
const toggleTheme = () => {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}

// 提供响应式数据（建议用 readonly 保护）
provide('theme', readonly(theme))
provide('toggleTheme', toggleTheme)

// 提供普通值
provide('appName', 'My App')
</script>
```

```vue
<!-- 子组件（任意层级） -->
<script setup>
import { inject } from 'vue'

// 注入
const theme = inject('theme')
const toggleTheme = inject('toggleTheme')

// 带默认值
const appName = inject('appName', 'Default App')

// 必须传入符号表示非必填，默认值为函数
const config = inject('config', () => ({ debug: false }), true)
</script>
```

### 6.2 类型安全的 InjectionKey

```typescript
// types.ts
import { InjectionKey, Ref } from 'vue'

export interface ThemeContext {
  theme: Ref<string>
  toggleTheme: () => void
}

export const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme')
```

```typescript
// Provider.vue
import { provide, readonly } from 'vue'
import { ThemeKey } from './types'

provide(ThemeKey, {
  theme: readonly(theme),
  toggleTheme
})

// Consumer.vue
import { inject } from 'vue'
import { ThemeKey } from './types'

const themeContext = inject(ThemeKey)
// themeContext.theme.value 有类型提示
```

### 6.3 实战：权限控制

```javascript
// usePermission.js
import { provide, inject, ref, computed } from 'vue'

const PermissionKey = Symbol('permission')

export function usePermissionProvider(roles) {
  const userRoles = ref(roles)
  
  const hasPermission = (requiredRole) => {
    return userRoles.value.includes(requiredRole)
  }
  
  provide(PermissionKey, {
    roles: readonly(userRoles),
    hasPermission
  })
}

export function usePermission() {
  const perms = inject(PermissionKey)
  if (!perms) {
    throw new Error('Permission not provided!')
  }
  return perms
}

// 使用
// 根组件
usePermissionProvider(['admin', 'user'])

// 子组件
const { hasPermission } = usePermission()
if (hasPermission('admin')) {
  // 显示管理员功能
}
```

***

## 7. 渲染函数与虚拟 DOM

### 7.1 h 函数基础

```javascript
import { h } from 'vue'

// h(type, props, children)

// 创建元素
const div = h('div', { class: 'container' }, 'Hello World')

// 多个子节点
const list = h('ul', { id: 'my-list' }, [
  h('li', 'Item 1'),
  h('li', 'Item 2'),
  h('li', 'Item 3')
])

// 事件处理
const button = h('button', {
  class: 'btn',
  onClick: () => console.log('clicked')
}, 'Click me')
```

### 7.2 纯 render 函数组件

```javascript
import { h, defineComponent, ref } from 'vue'

const Counter = defineComponent({
  setup() {
    const count = ref(0)
    
    return () => {
      return h('div', { class: 'counter' }, [
        h('p', `Count: ${count.value}`),
        h('button', {
          onClick: () => count.value++
        }, 'Increment'),
        h('button', {
          onClick: () => count.value--
        }, 'Decrement')
      ])
    }
  }
})
```

### 7.3 组件作为子节点

```javascript
import { h, defineComponent } from 'vue'

const Child = defineComponent({
  props: ['message'],
  setup(props) {
    return () => h('div', props.message)
  }
})

const Parent = defineComponent({
  setup() {
    return () => h('div', [
      h('h1', 'Parent Component'),
      h(Child, { message: 'Hello from parent' }),
      h(Child, { message: 'Another child' })
    ])
  }
})
```

### 7.4 插槽实现

```javascript
const Card = defineComponent({
  setup(props, { slots }) {
    return () => h('div', { class: 'card' }, [
      h('header', { class: 'card-header' }, slots.header?.()),
      h('main', { class: 'card-body' }, slots.default?.()),
      h('footer', { class: 'card-footer' }, slots.footer?.())
    ])
  }
})

// 使用（render 函数中）
h(Card, {}, {
  header: () => h('h3', 'Title'),
  default: () => h('p', 'Content'),
  footer: () => h('span', 'Footer')
})
```

### 7.5 虚拟 DOM 结构

```javascript
// VNode 基本结构
{
  __v_isVNode: true,
  type: 'div',           // 元素类型或组件
  props: { class: 'foo' },
  key: 'unique-key',
  ref: someRef,
  children: ['text'],    // 子节点
  suspense: null,
  ssContent: null,
  ssFallback: null,
  scopeId: null,
  slotScopeIds: null,
  axis: undefined
}
```

### 7.6 createVNode

```javascript
import { createVNode, render } from 'vue'

// 手动创建并挂载 VNode
const root = document.getElementById('app')
const vnode = createVNode('div', { class: 'hello' }, 'Hello Vue 3')
render(vnode, root)
```

***

## 8. 高级响应式工具

### 8.1 shallowRef / shallowReactive

浅层响应式，只追踪第一层：

```javascript
import { shallowRef, shallowReactive } from 'vue'

// shallowRef - 只追踪 .value 变化
const component = shallowRef({
  nested: { value: 1 }
})

component.value.nested.value = 2  // ❌ 不触发
component.value = {}              // ✅ 触发

// shallowReactive - 只追踪对象第一层
const state = shallowReactive({
  nested: { count: 0 }
})

state.nested.count++   // ❌ 不触发
state.nested = {}      // ✅ 触发

// 适用场景：大型不可变数据结构、第三方库实例
```

### 8.2 toRef / toRefs

保持解构时的响应性：

```javascript
import { reactive, toRefs, toRef } from 'vue'

const state = reactive({
  firstName: 'John',
  lastName: 'Doe',
  age: 30
})

// toRefs - 转换所有属性为 ref
const { firstName, lastName, age } = toRefs(state)
firstName.value = 'Jane'  // state.firstName 也变为 'Jane'

// toRef - 单个属性
const nameRef = toRef(state, 'firstName')
nameRef.value = 'Bob'     // state.firstName 也变为 'Bob'

// toRef - 带默认值
const nickname = toRef(state, 'nickname', 'Unknown')

// toRef - 计算 getter
const fullName = toRef(() => `${state.firstName} ${state.lastName}`)
```

### 8.3 readonly / shallowReadonly

创建不可变代理：

```javascript
import { reactive, readonly, shallowReadonly } from 'vue'

const original = reactive({
  count: 0,
  nested: { value: 1 }
})

// readonly - 深度只读
const copy = readonly(original)
// copy.count++           // ❌ 警告
// copy.nested.value++    // ❌ 警告

original.count++
console.log(copy.count)  // 1 - 仍然反映原值变化

// shallowReadonly - 只读第一层
const shallowCopy = shallowReadonly(original)
// shallowCopy.count++       // ❌ 警告
shallowCopy.nested.value++   // ✅ 允许（内层不是只读）
```

### 8.4 markRaw

标记对象永不响应式：

```javascript
import { reactive, markRaw } from 'vue'

const state = reactive({
  mutable: { foo: 1 },
  immutable: markRaw({ bar: 2 })
})

state.mutable.foo = 2    // ✅ 响应式
state.immutable.bar = 3  // ✅ 但不会触发响应式更新

// 适用场景：
// 1. 不应该转为代理的性能敏感对象
// 2. 第三方类实例
// 3. 已经自带响应式系统的对象
```

### 8.5 customRef

自定义 ref 的追踪和触发逻辑：

```javascript
import { customRef } from 'vue'

function useDebouncedRef(value, delay = 200) {
  let timer = null
  
  return customRef((track, trigger) => {
    let currentValue = value
    
    return {
      get() {
        track()
        return currentValue
      },
      set(newValue) {
        clearTimeout(timer)
        timer = setTimeout(() => {
          currentValue = newValue
          trigger()
        }, delay)
      }
    }
  })
}

// 使用
const debouncedSearch = useDebouncedRef('', 500)
debouncedSearch.value = 'hello'  // 500ms 后才触发更新
```

### 8.6 v-memo 指令

Vue 3.2+ 手动缓存：

```vue
<template>
  <!-- 只在 searchQuery 变化时重新渲染 -->
  <div v-memo="[searchQuery]">
    <Item 
      v-for="item in filteredItems" 
      :key="item.id"
      :search-query="searchQuery"
    />
  </div>
  
  <!-- 无 memo - 每次父组件更新都会重新渲染 -->
  <div>
    <Item v-for="item in items" :key="item.id" />
  </div>
</template>
```

***

## 9. 服务端渲染 (SSR)

### 9.1 基础 SSR

```javascript
// server.js
import { createSSRApp, ref, h } from 'vue'
import { renderToString } from '@vue/server-renderer'

const App = {
  setup() {
    const msg = ref('Hello Server!')
    return { msg }
  },
  template: `<div>{{ msg }}</div>`
}

async function render() {
  const app = createSSRApp(App)
  const html = await renderToString(app)
  console.log(html) // '<div>Hello Server!</div>'
  return html
}
```

### 9.2 流式渲染

```javascript
import { renderToNodeStream } from '@vue/server-renderer'
import { Readable } from 'stream'

// Node.js 流
function streamRender(res) {
  const app = createSSRApp(App)
  const stream = renderToNodeStream(app)
  
  res.setHeader('Content-Type', 'text/html')
  stream.pipe(res)
}

// Web Streams API
function webStreamRender() {
  const app = createSSRApp(App)
  const stream = renderToWebStream(app)
  
  return new Response(stream, {
    headers: { 'Content-Type': 'text/html' }
  })
}
```

### 9.3 SSR Context

```javascript
import { renderToString, createSSRApp } from 'vue'
import { renderToNodeStream } from '@vue/server-renderer'

async function renderWithContext() {
  const ctx = {}
  const app = createSSRApp(App)
  
  const html = await renderToString(app, ctx)
  
  // ctx.teleports 包含 teleport 的内容
  const teleports = ctx.teleports || {}
  
  return `
    <!DOCTYPE html>
    <html>
      <head>
        ${teleports.head || ''}
      </head>
      <body>
        <div id="app">${html}</div>
        ${teleports.body || ''}
      </body>
    </html>
  `
}
```

### 9.4 Teleport 在 SSR 中

```vue
<!-- 组件中使用 -->
<Teleport to="body">
  <div class="modal">Modal content</div>
</Teleport>

<!-- SSR 输出会在 ctx.teleports 中收集 -->
```

***

## 10. 底层原理

### 10.1 响应式系统原理

Vue 3 使用 ES6 Proxy 实现响应式：

```javascript
// 简化版实现
const targetsMap = new WeakMap()
let activeEffect = null

function track(target, key) {
  if (activeEffect) {
    let effects = targetsMap.get(target)
    if (!effects) {
      effects = new Map()
      targetsMap.set(target, effects)
    }
    let deps = effects.get(key)
    if (!deps) {
      deps = new Set()
      effects.set(key, deps)
    }
    deps.add(activeEffect)
  }
}

function trigger(target, key) {
  const effects = targetsMap.get(target)
  if (effects) {
    const deps = effects.get(key)
    if (deps) {
      deps.forEach(effect => effect())
    }
  }
}

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      const value = target[key]
      return typeof value === 'object' && value !== null 
        ? reactive(value) 
        : value
    },
    set(target, key, value) {
      target[key] = value
      trigger(target, key)
      return true
    }
  })
}

function effect(fn) {
  const runner = () => {
    activeEffect = runner
    fn()
    activeEffect = null
  }
  runner()
  return runner
}

// 使用
const data = reactive({ count: 0 })

effect(() => {
  console.log('count:', data.count)
})

data.count = 1  // 触发 effect
```

### 10.2 ref 实现原理

```javascript
function isRef(value) {
  return !!value && value.__v_isRef === true
}

function ref(value) {
  const refObject = {
    __v_isRef: true,
    get value() {
      // 读取时追踪依赖
      track(refObject, 'value')
      return value
    },
    set value(newValue) {
      if (newValue !== value) {
        value = newValue
        // 写入时触发更新
        trigger(refObject, 'value')
      }
    }
  }
  return refObject
}

function unref(value) {
  return isRef(value) ? value.value : value
}
```

### 10.3 computed 实现原理

```javascript
function computed(getter, setter) {
  const objectRef = reactive({})
  let result
  let dirty = true
  
  const effectFunc = () => {
    result = getter()
    dirty = false
  }
  
  effectFunc()
  
  return Object.assign(() => {
    if (dirty) {
      effectFunc()
    }
    track(objectRef, 'value')
    return result
  }, {
    get value() {
      if (dirty) {
        effectFunc()
      }
      track(objectRef, 'value')
      return result
    },
    set value(val) {
      setter?.(val)
    },
    __v_isRef: true,
    _cacheEffect: effectFunc
  })
}
```

### 10.4 虚拟 DOM Diff 算法

Vue 3 的 Diff 算法优化：

```
1. 双端比较
   - 头头比较
   - 尾尾比较
   - 头尾交叉比较
   - 尾头交叉比较

2. Keyed 节点 Diff
   - 使用新旧节点 key 映射
   - 最长递增子序列优化

3. Patch Flags 优化
   - TEXT: 只有文本变化
   - CLASS: 只有 class 变化
   - STYLE: 只有 style 变化
   - PROPS: 只有 props 变化
   - FULL_PROPS: 所有 props 可能变化
```

```javascript
// Patch Flags 示例
h('div', { class: 'foo' }, [-1 /* PATCH_KEYED_FRAGMENT */, [
  h('span', { key: 'a' }, 'A'),
  h('span', { key: 'b' }, 'B')
]])
```

### 10.5 编译优化

#### Tree Shaking

```javascript
// 只导入需要的 API
import { ref, computed } from 'vue'
// 未使用的 API 会被 tree-shaking 移除
```

#### 静态提升

```vue
<!-- 源码 -->
<div><span>静态文本</span></div>

<!-- 编译后 -->
const _hoisted_1 = { class: "foo" }
const _hoisted_2 = resolveComponent('span')
const _hoisted_3 = ["静态文本"]

return () => h('div', _hoisted_1, [
  h(_hoisted_2, null, _hoisted_3)
])
```

#### 补丁标志

```vue
<!-- 源码 -->
<div :class="activeClass">{{ text }}</div>

<!-- 编译后带有 patchFlag -->
h('div', {
  class: activeClass
}, text, 1 /* TEXT */)
```

### 10.6 Fragment、Teleport、Suspense 处理

```javascript
// Fragment - 多根节点
const vnode = createVNode(Fragment, null, [
  createVNode('div', null, 'Header'),
  createVNode('div', null, 'Main'),
  createVNode('div', null, 'Footer')
])

// Teleport
const teleportVNode = createVNode(Teleport, { to: 'body' }, [
  createVNode('div', null, 'Teleported content')
])

// Suspense
const suspenseVNode = createVNode(Suspense, null, {
  default: createVNode(asyncComponent),
  fallback: createVNode('div', null, 'Loading...')
})
```

***

## 附录：常用 API 速查

### 响应式 API

| API | 说明 |
|-----|------|
| ref | 创建响应式引用 |
| reactive | 创建响应式对象 |
| readonly | 创建只读代理 |
| shallowRef | 浅层响应式引用 |
| shallowReactive | 浅层响应式对象 |
| shallowReadonly | 浅层只读代理 |
| toRef | 创建属性 ref |
| toRefs | 转换为 refs 对象 |
| customRef | 自定义 ref |
| triggerRef | 触发 ref 更新 |
| unref | 解包 ref |
| isRef | 检查是否为 ref |
| isReactive | 检查是否响应式 |
| isReadonly | 检查是否只读 |
| isProxy | 检查是否为代理 |
| markRaw | 标记为非响应式 |
| toRaw | 获取原始对象 |
| effectScope | 创建作用域 |
| getCurrentScope | 获取当前作用域 |
| onScopeDispose | 作用域清理 |

### 计算与监视

| API | 说明 |
|-----|------|
| computed | 计算属性 |
| watch | 精确监视 |
| watchEffect | 自动追踪监视 |
| watchPostEffect | 下一个 DOM 更新后运行 |
| watchSyncEffect | 同步运行 |

### 生命周期

| API | 说明 |
|-----|------|
| onBeforeMount | 挂载前 |
| onMounted | 挂载后 |
| onBeforeUpdate | 更新前 |
| onUpdated | 更新后 |
| onBeforeUnmount | 卸载前 |
| onUnmounted | 卸载后 |
| onErrorCaptured | 错误捕获 |
| onActivated | 激活（KeepAlive） |
| onDeactivated | 失活（KeepAlive） |
| onServerPrefetch | 服务端预获取 |

### 组件相关

| API | 说明 |
|-----|------|
| defineComponent | 定义组件 |
| defineProps | 定义 props（setup） |
| defineEmits | 定义 emits（setup） |
| defineExpose | 暴露属性 |
| defineOptions | 定义选项（setup） |
| defineSlots | 获取插槽（setup） |
| defineModel | 定义双向绑定（setup） |
| getCurrentInstance | 获取当前实例 |
| withDefaults | props 默认值 |
| withModifiers | 修饰事件 |
| withKeys | 键修饰符 |

### 工具函数

| API | 说明 |
|-----|------|
| nextTick | 下一个 DOM 更新周期 |
| h | 创建 VNode |
| resolveComponent | 解析组件 |
| resolveDirective | 解析指令 |
| mergeProps | 合并 props |
| cloneVNode | 克隆 VNode |
| normalizeClass | 规范化 class |
| normalizeStyle | 规范化 style |
| openBlock | 开启块追踪 |
| setBlockTracking | 设置块追踪 |
| createElementBlock | 创建元素块 |
| createBlock | 创建块 |

***

*文档生成日期：2026 年 4 月 15 日*
*基于 Vue 3.x 官方文档整理*
