Vue3响应式系统深入解析

Vue3响应式系统深入解析

前言

Vue 3 的响应式系统是其核心特性之一,相比 Vue 2 有了显著的改进和性能优化。本文将深入解析 Vue 3 响应式系统的实现原理、核心 API 以及使用技巧,帮助开发者更好地理解和运用 Vue 3 的响应式能力。

一、响应式系统演进

1. Vue 2 与 Vue 3 响应式系统对比

Vue 2 的响应式系统基于 Object.defineProperty 实现,而 Vue 3 则采用了 ES6 的 Proxy。这种变化带来了多方面的改进:

特性 Vue 2 (Object.defineProperty) Vue 3 (Proxy)
属性添加/删除 不支持直接监听,需要 Vue.set/Vue.delete 原生支持监听属性添加和删除
数组索引和长度 对数组索引和长度的变化支持有限 完全支持数组索引和长度的变化
嵌套对象 需要递归遍历所有层级属性 懒代理,仅在访问时才代理嵌套对象
性能 初始化较慢,内存占用较大 初始化更快,内存占用更小
类型支持 对 TypeScript 支持有限 更好的 TypeScript 集成支持

2. Proxy 的优势

ES6 Proxy 提供了拦截对象操作的能力,Vue 3 利用这一特性实现了更强大、更灵活的响应式系统:

  1. 完整的对象操作拦截:可以拦截 get、set、deleteProperty 等更多操作
  2. 懒代理:只在实际访问属性时才递归代理子属性
  3. 更好的数组支持:可以直接监听数组索引、长度变化和数组方法
  4. 无需手动维护依赖追踪:依赖收集和触发更新更加自动化和精确

二、核心响应式 API 详解

1. reactive

reactive 函数用于创建一个响应式对象或数组:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { reactive } from 'vue';

// 创建响应式对象
const state = reactive({
  count: 0,
  user: {
    name: 'Alice',
    age: 25
  },
  tags: ['Vue', 'JavaScript', 'TypeScript']
});

// 自动触发更新
state.count++; // 触发更新
state.user.name = 'Bob'; // 触发更新
state.tags.push('React'); // 触发更新

reactive 的工作原理是返回一个原始对象的 Proxy 代理,通过陷阱函数拦截对对象的操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// reactive 简化实现原理
function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      // 依赖收集
      track(target, key);
      // 获取原始值
      const result = Reflect.get(target, key, receiver);
      // 懒代理:如果是对象,递归代理
      if (typeof result === 'object' && result !== null) {
        return reactive(result);
      }
      return result;
    },
    set(target, key, value, receiver) {
      const oldValue = target[key];
      // 设置新值
      const result = Reflect.set(target, key, value, receiver);
      // 触发更新
      if (oldValue !== value) {
        trigger(target, key);
      }
      return result;
    },
    deleteProperty(target, key) {
      const hasKey = key in target;
      const result = Reflect.deleteProperty(target, key);
      // 如果属性存在并成功删除,触发更新
      if (hasKey) {
        trigger(target, key, 'delete');
      }
      return result;
    }
  });
}

2. ref

ref 函数用于创建一个包装基本类型值的响应式引用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { ref } from 'vue';

// 创建响应式引用
const count = ref(0);
const message = ref('Hello Vue 3');
const isLoading = ref(false);

// 通过 .value 访问和修改
console.log(count.value); // 0
count.value++; // 触发更新
message.value = 'Hello Reactive'; // 触发更新

// 在模板中自动解包
// <template>
//   <div>{{ count }}</div> <!-- 不需要 .value -->
// </template>

ref 的工作原理是创建一个包含 .value 属性的包装对象,然后对 .value 属性进行响应式处理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ref 简化实现原理
function ref(value) {
  const refObject = {
    get value() {
      // 依赖收集
      track(refObject, 'value');
      return value;
    },
    set value(newValue) {
      if (value !== newValue) {
        value = newValue;
        // 触发更新
        trigger(refObject, 'value');
      }
    }
  };
  
  // 添加 __v_isRef 标识
  Object.defineProperty(refObject, '__v_isRef', {
    value: true
  });
  
  return refObject;
}

3. computed

computed 函数用于创建一个计算属性,它会根据响应式依赖自动计算并缓存结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { ref, computed } from 'vue';

const count = ref(0);

// 创建计算属性
const doubleCount = computed(() => count.value * 2);
const isEven = computed(() => count.value % 2 === 0);

// 计算属性会根据依赖自动更新
count.value = 1; // doubleCount 自动变为 2,isEven 自动变为 false

// 计算属性默认是只读的
// doubleCount.value = 10; // 错误:计算属性是只读的

// 创建可写计算属性
const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (newValue) => {
    const [first, last] = newValue.split(' ');
    firstName.value = first;
    lastName.value = last;
  }
});

computed 的工作原理是维护一个缓存值和脏标志,只有当依赖变化时才重新计算:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// computed 简化实现原理
function computed(getterOrOptions) {
  let getter;
  let setter;
  
  // 处理传入的是函数还是对象
  if (typeof getterOrOptions === 'function') {
    getter = getterOrOptions;
    setter = () => console.warn('Computed property is readonly');
  } else {
    getter = getterOrOptions.get;
    setter = getterOrOptions.set;
  }
  
  let dirty = true;
  let value;
  let computed;
  
  // 创建计算对象
  const runner = effect(getter, {
    lazy: true,
    scheduler: () => {
      // 依赖变化时标记为脏
      dirty = true;
      // 触发依赖此计算属性的更新
      trigger(computed, 'value');
    }
  });
  
  computed = {
    get value() {
      // 依赖收集
      track(computed, 'value');
      // 只有脏时才重新计算
      if (dirty) {
        value = runner();
        dirty = false;
      }
      return value;
    },
    set value(newValue) {
      setter(newValue);
    }
  };
  
  return computed;
}

4. watch

watch 函数用于监听响应式数据的变化并执行回调:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { ref, reactive, watch } from 'vue';

// 监听单个 ref
const count = ref(0);
watch(count, (newCount, oldCount) => {
  console.log(`count changed from ${oldCount} to ${newCount}`);
});

// 监听 reactive 对象的属性
const state = reactive({ count: 0, name: 'Vue' });
watch(
  () => state.count,
  (newCount, oldCount) => {
    console.log(`count changed from ${oldCount} to ${newCount}`);
  }
);

// 监听多个源
watch([count, () => state.name], ([newCount, newName], [oldCount, oldName]) => {
  console.log(`count: ${oldCount} -> ${newCount}`);
  console.log(`name: ${oldName} -> ${newName}`);
});

// 深度监听
watch(
  () => state,
  (newState, oldState) => {
    console.log('State changed:', newState);
  },
  { deep: true }
);

// 立即执行
watch(count, (newCount) => {
  console.log('Count:', newCount);
}, { immediate: true });

5. watchEffect

watchEffect 函数用于创建一个副作用函数,并自动追踪其依赖的响应式数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { ref, watchEffect } from 'vue';

const count = ref(0);
const name = ref('Vue');

// 创建副作用,自动追踪所有依赖
const stop = watchEffect(() => {
  console.log(`Count: ${count.value}, Name: ${name.value}`);
});

// 当不再需要监听时停止副作用
// stop();

// 清除副作用
watchEffect((onCleanup) => {
  // 副作用执行
  const timer = setTimeout(() => {
    console.log('Timer executed');
  }, 1000);
  
  // 清除函数会在下一次副作用执行前或组件卸载时调用
  onCleanup(() => {
    clearTimeout(timer);
  });
});

三、响应式系统的实现原理

1. 依赖收集与触发

Vue 3 响应式系统的核心是依赖收集和触发更新机制:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// 依赖收集和触发的核心实现

// 当前活跃的副作用函数
let activeEffect;

// 副作用栈,处理嵌套副作用
const effectStack = [];

// 副作用函数类
class ReactiveEffect {
  constructor(fn, scheduler = null) {
    this.fn = fn;
    this.scheduler = scheduler;
    this.deps = [];
    this.active = true;
  }
  
  run() {
    // 非激活状态只执行函数,不收集依赖
    if (!this.active) {
      return this.fn();
    }
    
    // 确保副作用函数正确入栈和出栈
    if (!effectStack.includes(this)) {
      try {
        // 入栈
        effectStack.push(this);
        // 设置当前活跃副作用
        activeEffect = this;
        // 执行副作用函数,触发依赖收集
        return this.fn();
      } finally {
        // 出栈
        effectStack.pop();
        // 恢复之前的活跃副作用
        activeEffect = effectStack[effectStack.length - 1];
      }
    }
  }
  
  stop() {
    if (this.active) {
      // 清理所有依赖
      cleanupEffect(this);
      this.active = false;
    }
  }
}

// 创建副作用
function effect(fn, options = {}) {
  const _effect = new ReactiveEffect(fn, options.scheduler);
  
  // 立即执行一次
  _effect.run();
  
  // 返回停止函数
  const runner = _effect.run.bind(_effect);
  runner.effect = _effect;
  return runner;
}

// 依赖收集
function track(target, key) {
  if (!activeEffect) return;
  
  // 获取 target 的依赖映射
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  
  // 获取 key 对应的副作用集合
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  
  // 将当前活跃副作用添加到集合
  if (!dep.has(activeEffect)) {
    dep.add(activeEffect);
    // 同时记录依赖到副作用的 deps 中
    activeEffect.deps.push(dep);
  }
}

// 触发更新
function trigger(target, key, type) {
  // 获取依赖映射
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  
  // 获取要执行的副作用集合
  const effects = new Set();
  
  // 添加 key 对应的副作用
  if (key !== undefined) {
    const deps = depsMap.get(key);
    if (deps) {
      deps.forEach(effect => effects.add(effect));
    }
  }
  
  // 执行副作用
  effects.forEach(effect => {
    // 如果有调度器,则使用调度器
    if (effect.scheduler) {
      effect.scheduler();
    } else {
      // 否则直接运行副作用
      effect.run();
    }
  });
}

2. 响应式系统的内部结构

Vue 3 响应式系统的内部结构可以概括为以下几个部分:

  1. 原始数据:用户定义的数据对象或值
  2. 代理对象:通过 Proxy 创建的响应式代理
  3. 依赖映射:跟踪数据与副作用函数之间的关系
  4. 副作用函数:响应数据变化而执行的函数
  5. 调度器:控制副作用函数的执行时机和方式
1
原始数据 -> Proxy 代理 -> 拦截操作 -> 依赖收集/触发更新 -> 副作用函数执行

3. 响应式数据的类型

Vue 3 支持多种类型的响应式数据:

  • reactive 对象:通过 reactive() 创建的响应式对象
  • ref 对象:通过 ref() 创建的包含 .value 的响应式引用
  • computed 对象:通过 computed() 创建的计算属性
  • readonly 对象:通过 readonly() 创建的只读响应式对象

四、高级使用技巧

1. 响应式数据的解构问题

解构赋值会丢失响应性,需要使用 toRefstoRef 来保留响应性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { reactive, toRefs, toRef } from 'vue';

const state = reactive({ count: 0, name: 'Vue' });

// 错误:解构后丢失响应性
const { count, name } = state;
count = 1; // 不会触发更新

// 正确:使用 toRefs 保留响应性
const { count: countRef, name: nameRef } = toRefs(state);
countRef.value = 1; // 会触发更新

// 只转换单个属性
const countRef = toRef(state, 'count');

2. 响应式数据的类型转换

Vue 3 提供了多个工具函数用于响应式数据的类型转换:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { reactive, ref, toRefs, toRef, isRef, isReactive, isProxy } from 'vue';

const reactiveObj = reactive({ count: 0 });
const countRef = ref(0);
const plainObj = { count: 0 };

// 检查是否为 ref
console.log(isRef(countRef)); // true
console.log(isRef(reactiveObj)); // false

// 检查是否为 reactive
console.log(isReactive(reactiveObj)); // true
console.log(isReactive(countRef)); // false

// 检查是否为代理对象(reactive 或 readonly)
console.log(isProxy(reactiveObj)); // true
console.log(isProxy(countRef)); // false

// 将 ref 转换为原始值
const count = unref(countRef); // 等同于 countRef.value

// 如果是 ref 则返回其 value,否则返回原始值
function useFeature(id) {
  const unwrappedId = unref(id); // id 可以是 ref 或普通值
  // ...
}

3. 响应式数据的深拷贝

处理响应式数据的深拷贝需要特殊处理,避免丢失响应性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { reactive, toRaw } from 'vue';

const state = reactive({
  user: { name: 'Alice', age: 25 },
  tags: ['Vue', 'React']
});

// 获取原始数据,用于序列化等操作
const rawState = toRaw(state);
const json = JSON.stringify(rawState);

// 深拷贝响应式数据
function deepCloneReactive(target) {
  if (typeof target !== 'object' || target === null) {
    return target;
  }
  
  // 处理数组
  if (Array.isArray(target)) {
    const result = reactive([]);
    for (let i = 0; i < target.length; i++) {
      result[i] = deepCloneReactive(target[i]);
    }
    return result;
  }
  
  // 处理对象
  const result = reactive({});
  for (const key in target) {
    if (Object.prototype.hasOwnProperty.call(target, key)) {
      result[key] = deepCloneReactive(target[key]);
    }
  }
  return result;
}

4. 自定义响应式行为

可以通过 customRef 创建自定义的响应式引用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { customRef } from 'vue';

// 创建带有防抖功能的 ref
function useDebouncedRef(value, delay = 300) {
  let timeout;
  
  return customRef((track, trigger) => ({
    get() {
      // 依赖收集
      track();
      return value;
    },
    set(newValue) {
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        value = newValue;
        // 触发更新
        trigger();
      }, delay);
    }
  }));
}

// 使用自定义 ref
const searchQuery = useDebouncedRef('');

// 创建可缓存的 ref
function useCachedRef(key, initialValue) {
  // 尝试从 localStorage 获取缓存值
  const cachedValue = localStorage.getItem(key);
  let value = cachedValue !== null ? JSON.parse(cachedValue) : initialValue;
  
  return customRef((track, trigger) => ({
    get() {
      track();
      return value;
    },
    set(newValue) {
      value = newValue;
      // 缓存到 localStorage
      localStorage.setItem(key, JSON.stringify(newValue));
      trigger();
    }
  }));
}

五、常见问题与解决方案

1. 响应式数据更新但视图不渲染

问题分析

  • 可能是因为修改了未被代理的属性
  • 可能是因为在非响应式上下文中修改了数据
  • 可能是因为修改了数组的非响应式方法

解决方案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { reactive, ref, nextTick } from 'vue';

// 问题:直接修改数组长度不触发更新
const arr = reactive([1, 2, 3]);
arr.length = 0; // 不会触发更新

// 解决方案:使用响应式方法
arr.splice(0); // 会触发更新

// 问题:直接添加不存在的属性
const obj = reactive({ name: 'Vue' });
obj.age = 3; // Vue 3 已经支持这种方式

// 问题:在定时器中修改数据
const count = ref(0);
setTimeout(() => {
  count.value++; // 应该会触发更新,但如果不触发...
  // 可以使用 nextTick 确保 DOM 更新
  nextTick(() => {
    // DOM 已更新
  });
}, 1000);

2. 循环引用导致的问题

问题分析: 循环引用可能导致无限递归和栈溢出,特别是在序列化或深拷贝时。

解决方案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { reactive } from 'vue';

// 创建循环引用的响应式对象
const parent = reactive({ name: 'Parent' });
const child = reactive({ name: 'Child' });

// 创建循环引用
parent.child = child;
child.parent = parent;

// 序列化时的解决方案
function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) {
        return '[Circular Reference]';
      }
      seen.add(value);
    }
    return value;
  });
}

console.log(safeStringify(parent));

3. 性能优化技巧

避免不必要的响应式转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { reactive, markRaw } from 'vue';

// 对于不需要响应式的大型对象,使用 markRaw 跳过响应式转换
const state = reactive({
  // 普通响应式数据
  count: 0,
  
  // 第三方库实例、DOM 对象等不需要响应式的数据
  chartInstance: markRaw(new Chart()),
  
  // 大型静态配置对象
  config: markRaw({
    // 大量配置项...
  })
});

合理使用 computed 缓存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { computed } from 'vue';

// 对于复杂计算,使用 computed 缓存结果
const expensiveResult = computed(() => {
  // 复杂计算逻辑
  let result = 0;
  for (let i = 0; i < largeArray.length; i++) {
    result += complexCalculation(largeArray[i]);
  }
  return result;
});

避免在模板中进行复杂计算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<template>
  <!-- 不推荐在模板中进行复杂计算 -->
  <div>{{ items.filter(item => item.active).length }}</div>
  
  <!-- 推荐使用计算属性 -->
  <div>{{ activeItemsCount }}</div>
</template>

<script setup>
import { computed } from 'vue';

// 使用计算属性缓存结果
const activeItemsCount = computed(() => {
  return items.filter(item => item.active).length;
});
</script>

六、响应式系统与组合式 API 结合

1. 构建可复用的响应式逻辑

使用组合式 API 封装可复用的响应式逻辑:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// src/composables/useCounter.js
import { ref, computed } from 'vue';

export function useCounter(initialValue = 0) {
  // 响应式状态
  const count = ref(initialValue);
  
  // 计算属性
  const isEven = computed(() => count.value % 2 === 0);
  const isPositive = computed(() => count.value > 0);
  
  // 修改状态的方法
  function increment(step = 1) {
    count.value += step;
  }
  
  function decrement(step = 1) {
    count.value -= step;
  }
  
  function reset() {
    count.value = initialValue;
  }
  
  // 返回需要暴露的状态和方法
  return {
    count,
    isEven,
    isPositive,
    increment,
    decrement,
    reset
  };
}

// 使用示例
import { useCounter } from '@/composables/useCounter';

const { count, increment, reset } = useCounter(10);
increment(); // count.value 变为 11
reset(); // count.value 重置为 10

2. 构建响应式的 API 调用

封装响应式的 API 调用逻辑:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// src/composables/useApi.js
import { ref, reactive } from 'vue';

export function useApi() {
  const loading = ref(false);
  const error = ref(null);
  
  async function request(url, options = {}) {
    loading.value = true;
    error.value = null;
    
    try {
      const response = await fetch(url, {
        ...options,
        headers: {
          'Content-Type': 'application/json',
          ...options.headers
        }
      });
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      const data = await response.json();
      return data;
    } catch (err) {
      error.value = err.message;
      throw err;
    } finally {
      loading.value = false;
    }
  }
  
  // GET 请求
  function get(url, params = {}) {
    const queryString = new URLSearchParams(params).toString();
    const fullUrl = queryString ? `${url}?${queryString}` : url;
    
    return request(fullUrl, {
      method: 'GET'
    });
  }
  
  // POST 请求
  function post(url, data = {}) {
    return request(url, {
      method: 'POST',
      body: JSON.stringify(data)
    });
  }
  
  // PUT 请求
  function put(url, data = {}) {
    return request(url, {
      method: 'PUT',
      body: JSON.stringify(data)
    });
  }
  
  // DELETE 请求
  function del(url) {
    return request(url, {
      method: 'DELETE'
    });
  }
  
  return {
    loading,
    error,
    get,
    post,
    put,
    delete: del
  };
}

// 使用示例
import { useApi } from '@/composables/useApi';

const { loading, error, get, post } = useApi();

async function fetchUsers() {
  try {
    const users = await get('/api/users');
    // 处理用户数据
  } catch (err) {
    // 错误处理
  }
}

总结

Vue 3 的响应式系统是其最强大的特性之一,通过使用 Proxy 实现,相比 Vue 2 提供了更完整、更高效的响应式能力。本文深入解析了 Vue 3 响应式系统的核心 API、实现原理和高级使用技巧,包括:

  1. 响应式系统演进:从 Vue 2 的 Object.defineProperty 到 Vue 3 的 Proxy 的转变
  2. 核心响应式 API:reactive、ref、computed、watch 和 watchEffect 的使用和原理
  3. 实现原理:依赖收集和触发更新的内部机制
  4. 高级使用技巧:响应式数据的解构、类型转换、深拷贝和自定义响应式行为
  5. 常见问题与解决方案:响应式数据更新但视图不渲染、循环引用问题和性能优化
  6. 与组合式 API 结合:构建可复用的响应式逻辑和响应式 API 调用

掌握 Vue 3 响应式系统的原理和使用技巧,对于构建高性能、可维护的 Vue 应用至关重要。通过合理使用响应式 API 和遵循最佳实践,开发者可以充分发挥 Vue 3 的优势,创建出优秀的前端应用。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计