当前位置:首页 > 未命名 > 正文内容

Vue.js 3.0组合式API深度实践

廖万里9小时前未命名1

Vue 3新特性

Vue 3带来了革命性的变化:组合式API、更好的TypeScript支持、更快的渲染性能和更小的打包体积。

Vue 2 vs Vue 3

特性Vue 2Vue 3
API风格选项式API组合式API
响应式Object.definePropertyProxy
TypeScript支持有限原生支持
Fragments不支持支持多根节点
Teleport不支持支持

组合式API基础

setup函数




响应式API

import { ref, reactive, toRef, toRefs, shallowRef, shallowReactive } from 'vue';

// ref - 用于基本类型(也可用于对象)
const count = ref(0);
count.value++;  // 需要.value访问

// reactive - 用于对象/数组
const user = reactive({
  name: 'Alice',
  age: 25
});
user.age++;  // 直接访问

// toRef - 将reactive属性转为ref
const nameRef = toRef(user, 'name');

// toRefs - 解构reactive对象
const { name, age } = toRefs(user);

// shallowRef/shallowReactive - 浅层响应式
const shallowUser = shallowRef({ name: 'Bob' });
// 只追踪.value的变化,不追踪内部属性

// readonly - 只读
const readonlyUser = readonly(user);

组合式函数

自定义Hook

// composables/useCounter.js
import { ref, computed } from 'vue';

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

// 使用
import { useCounter } from './composables/useCounter';

setup() {
  const { count, increment } = useCounter(10);
  return { count, increment };
}

API请求Hook

// composables/useFetch.js
import { ref, watchEffect } from 'vue';

export function useFetch(url) {
  const data = ref(null);
  const error = ref(null);
  const loading = ref(false);
  
  async function fetchData() {
    loading.value = true;
    error.value = null;
    
    try {
      const response = await fetch(url.value);
      if (!response.ok) throw new Error('Network error');
      data.value = await response.json();
    } catch (e) {
      error.value = e;
    } finally {
      loading.value = false;
    }
  }
  
  if (url.value) fetchData();
  
  // 响应式URL变化时重新获取
  watchEffect(() => {
    if (url.value) fetchData();
  });
  
  return { data, error, loading, refetch: fetchData };
}

// 使用
import { useFetch } from './composables/useFetch';

setup() {
  const userId = ref(1);
  const url = computed(() => `/api/users/${userId.value}`);
  const { data: user, loading, error } = useFetch(url);
  
  return { user, loading, error, userId };
}

生命周期

import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured
} from 'vue';

export default {
  setup() {
    onBeforeMount(() => {
      console.log('Before mount');
    });
    
    onMounted(() => {
      console.log('Mounted');
      // DOM已可用
    });
    
    onBeforeUpdate(() => {
      console.log('Before update');
    });
    
    onUpdated(() => {
      console.log('Updated');
    });
    
    onBeforeUnmount(() => {
      console.log('Before unmount');
      // 清理定时器、事件监听等
    });
    
    onUnmounted(() => {
      console.log('Unmounted');
    });
    
    onErrorCaptured((err, instance, info) => {
      console.error('Error captured:', err);
      return false; // 阻止错误继续传播
    });
  }
};

依赖注入

// 父组件 - 提供依赖
import { provide, ref } from 'vue';

export default {
  setup() {
    const theme = ref('dark');
    const user = ref({ name: 'Alice' });
    
    provide('theme', theme);
    provide('user', user);
    provide('updateTheme', (newTheme) => {
      theme.value = newTheme;
    });
    
    return { theme, user };
  }
};

// 子组件 - 注入依赖
import { inject } from 'vue';

export default {
  setup() {
    const theme = inject('theme', 'light'); // 默认值
    const user = inject('user');
    const updateTheme = inject('updateTheme');
    
    return { theme, user, updateTheme };
  }
};

Teleport组件






最佳实践

  1. 优先使用组合式API:更好的代码组织和复用
  2. 合理命名composables:useXxx命名约定
  3. 解耦组件逻辑:将复杂逻辑提取到composables
  4. 使用TypeScript:获得完整类型支持
  5. 避免过度使用reactive:简单数据用ref

Vue 3的组合式API是现代Vue开发的最佳选择,掌握它能够构建更可维护的应用。

Vue 3 Composition API Reactivity Vue 3核心特性

本文链接:https://www.kkkliao.cn/?id=757 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。