老梁聊全栈系列:Vue3核心与组合式API深度解析

一、Vue3架构革新

1.1 响应式系统重写

Vue3使用Proxy替代了Vue2的Object.defineProperty,带来了显著的性能提升和功能增强:

  • 全范围的响应式检测:可以检测对象属性的添加/删除

  • 更好的数组支持:直接监听数组变化无需hack

  • 更高效的内存使用:惰性响应式处理

  • 嵌套对象自动解包:无需特殊处理

1.2 虚拟DOM优化

Vue3的虚拟DOM进行了多项优化:

  • 编译时静态节点标记:跳过静态子树比对

  • 区块树(Block Tree):动态节点追踪更精确

  • 缓存事件处理函数:避免不必要的重新渲染

  • 更高效的diff算法:最长递增子序列优化

二、组合式API核心概念

2.1 setup函数

setup是组合式API的入口点,在组件创建之前执行:

setup特性

  • 在beforeCreate之前调用

  • 没有this上下文

  • 返回的对象会暴露给模板

  • 可以返回渲染函数

2.2 响应式基础

2.2.1 ref与reactive
特性 ref reactive
创建方式 ref(value) reactive(object)
访问值 .value 直接访问属性
适用场景 基本类型/对象引用 复杂对象
模板自动解包 需要.value但在模板中自动解包 直接使用
复制代码
const counter = ref(0); // 基本类型
const user = reactive({ name: 'Bob' }); // 复杂对象
​
// 在JS中
counter.value++; 
user.name = 'Alice';
​
// 在模板中
// <div>{{ counter }}</div>
// <div>{{ user.name }}</div>
2.2.2 computed与watch

计算属性

复制代码
const double = computed(() => count.value * 2);

侦听器

复制代码
// 单个源
watch(count, (newVal, oldVal) => {
  console.log(`count变化: ${oldVal} -> ${newVal}`);
});
​
// 多个源
watch([count, user], ([newCount, newUser], [oldCount, oldUser]) => {
  // 响应变化
});

2.3 生命周期钩子

组合式API的生命周期钩子:

选项式API 组合式API
beforeCreate 不需要(使用setup代替)
created 不需要(使用setup代替)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
复制代码
import { onMounted, onUnmounted } from 'vue';
​
setup() {
  onMounted(() => {
    console.log('组件挂载完成');
  });
  
  onUnmounted(() => {
    console.log('组件即将卸载');
  });
}

三、逻辑复用模式

3.1 自定义组合函数

将相关逻辑提取为可复用函数:

复制代码
// 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(10);
    
    return {
      count,
      increment
    };
  }
};

3.2 与第三方库集成

将第三方库封装为组合函数:

复制代码
// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue';
​
export function useMouse() {
  const x = ref(0);
  const y = ref(0);
  
  function update(event) {
    x.value = event.pageX;
    y.value = event.pageY;
  }
  
  onMounted(() => window.addEventListener('mousemove', update));
  onUnmounted(() => window.removeEventListener('mousemove', update));
  
  return { x, y };
}

四、与模板的交互

4.1 模板引用(ref)

访问DOM元素或组件实例:

复制代码
<template>
  <input ref="inputRef" />
</template>
​
<script>
import { ref, onMounted } from 'vue';
​
export default {
  setup() {
    const inputRef = ref(null);
    
    onMounted(() => {
      inputRef.value.focus();
    });
    
    return {
      inputRef
    };
  }
};
</script>

4.2 依赖注入(provide/inject)

跨组件层级传递数据:

复制代码
// 祖先组件
import { provide, ref } from 'vue';
​
setup() {
  const theme = ref('dark');
  
  provide('theme', theme);
  
  return {
    theme
  };
}
​
// 后代组件
import { inject } from 'vue';
​
setup() {
  const theme = inject('theme', 'light'); // 默认值'light'
  
  return {
    theme
  };
}

五、TypeScript集成

5.1 组件Props类型定义

复制代码
interface Props {
  title: string;
  size?: 'small' | 'medium' | 'large';
  disabled?: boolean;
}
​
export default defineComponent({
  props: {
    title: {
      type: String as PropType<Props['title']>,
      required: true
    },
    size: {
      type: String as PropType<Props['size']>,
      default: 'medium'
    },
    disabled: Boolean
  },
  setup(props: Props) {
    // 使用props
  }
});

5.2 组合函数类型定义

复制代码
import { Ref } from 'vue';
​
interface CounterOptions {
  min?: number;
  max?: number;
}
​
interface CounterReturn {
  count: Ref<number>;
  increment: () => void;
  decrement: () => void;
}
​
export function useCounter(
  initialValue = 0, 
  options: CounterOptions = {}
): CounterReturn {
  const count = ref(initialValue);
  
  function increment() {
    if (options.max !== undefined && count.value >= options.max) return;
    count.value++;
  }
  
  function decrement() {
    if (options.min !== undefined && count.value <= options.min) return;
    count.value--;
  }
  
  return {
    count,
    increment,
    decrement
  };
}

六、最佳实践

6.1 代码组织原则

  1. 按功能而非选项类型组织代码

    • 将相关的数据、计算属性、方法放在一起

    • 避免将setup函数变成"大杂烩"

  2. 合理拆分组合函数

    • 保持组合函数单一职责

    • 控制组合函数复杂度

  3. 命名规范

    • 组合函数使用use前缀(如useFetch)

    • ref变量保持描述性命名

6.2 性能考量

  1. 避免不必要的响应式

    复制代码
    // 不需要响应式的数据
    const staticData = { title: 'About' };
  2. 合理使用shallowRef/shallowReactive

    复制代码
    const largeList = shallowRef([]); // 内部不转换响应式
  3. 优化计算属性

    复制代码
    // 只有当依赖变化时才重新计算
    const filteredList = computed(() => 
      largeList.value.filter(item => item.active)
    );

Vue3的组合式API代表了前端组件设计的新范式,它通过更灵活的代码组织方式、更好的TypeScript集成和更高效的逻辑复用能力,显著提升了复杂组件的可维护性。掌握这些核心概念和技术要点,开发者能够构建更健壮、更易扩展的Vue应用程序

相关推荐
想吃火锅10059 小时前
【leetcode】405.数字转换为十六进制数js
开发语言·javascript·ecmascript
阿猫的故乡11 小时前
Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定
前端·javascript·vue.js
裕波12 小时前
Vue&ViteConf 2026 将于 7 月 18 日在上海举办,尤雨溪将现场发表主题演讲
vue.js·vite
小和尚敲木头12 小时前
vue3 vite动态拼接图片路径
javascript
我叫黑大帅12 小时前
前端如何竖屏固定视口背景
前端·javascript·面试
不会敲代码113 小时前
我花了三天时间,终于把 Cookie、XSS、CSRF 和浏览器存储给整明白了
javascript·面试
贩卖黄昏的熊13 小时前
flex 布局快速梳理
开发语言·javascript·css3·html5
swipe13 小时前
Mem0 x Agent 实战系列:分层记忆 + 三路召回,搭建真正可用的长期记忆层
前端·javascript·面试
kyriewen13 小时前
手写 call、apply、bind:从原理到实现,附 3 个最容易忽略的边界情况
前端·javascript·面试