Vue3组合式API实战:构建更可维护的组件

Vue3组合式API实战:构建更可维护的组件

大家好,我是蔓蔓。Vue3的组合式API是一个非常强大的特性,它让我们能够更好地组织和复用代码。今天我来和大家分享Vue3组合式API的实战技巧。

什么是组合式API

Options API vs Composition API

javascript 复制代码
// Options API - 按选项组织代码
export default {
  data() {
    return {
      count: 0,
      name: '蔓蔓'
    };
  },
  methods: {
    increment() {
      this.count++;
    }
  },
  computed: {
    doubleCount() {
      return this.count * 2;
    }
  }
};

// Composition API - 按功能组织代码
import { ref, computed } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const name = ref('蔓蔓');
    
    const increment = () => {
      count.value++;
    };
    
    const doubleCount = computed(() => count.value * 2);
    
    return { count, name, increment, doubleCount };
  }
};

响应式基础

javascript 复制代码
import { ref, reactive, computed, watch, watchEffect } from 'vue';

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

// reactive - 用于对象
const state = reactive({
  name: '蔓蔓',
  age: 25
});
state.name = '新名字'; // 直接访问

// computed - 计算属性
const doubleCount = computed(() => count.value * 2);

// watch - 监听变化
watch(count, (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`);
});

// watchEffect - 自动追踪依赖
watchEffect(() => {
  console.log(`count is: ${count.value}`);
});

实战案例

组合式函数

javascript 复制代码
// useCounter.js - 可复用的组合式函数
import { ref, computed } from 'vue';

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

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

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

异步数据获取

javascript 复制代码
// useFetch.js - 数据获取组合式函数
import { ref, onMounted, onUnmounted } from 'vue';

export function useFetch(url, options = {}) {
  const data = ref(null);
  const error = ref(null);
  const loading = ref(true);
  let controller = null;
  
  const fetchData = async () => {
    loading.value = true;
    error.value = null;
    controller = new AbortController();
    
    try {
      const response = await fetch(url, {
        ...options,
        signal: controller.signal
      });
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      data.value = await response.json();
    } catch (err) {
      if (err.name !== 'AbortError') {
        error.value = err.message;
      }
    } finally {
      loading.value = false;
    }
  };
  
  onMounted(fetchData);
  
  onUnmounted(() => {
    if (controller) {
      controller.abort();
    }
  });
  
  return {
    data,
    error,
    loading,
    refetch: fetchData
  };
}

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

export default {
  setup() {
    const { data: user, loading, error } = useFetch('/api/user');
    return { user, loading, error };
  }
};

表单处理

javascript 复制代码
// useForm.js - 表单处理组合式函数
import { reactive, computed } from 'vue';

export function useForm(initialValues) {
  const form = reactive({ ...initialValues });
  const errors = reactive({});
  
  const validateField = (fieldName, rules) => {
    errors[fieldName] = null;
    
    for (const rule of rules) {
      if (rule.required && !form[fieldName]) {
        errors[fieldName] = rule.message || '此字段必填';
        return false;
      }
      if (rule.pattern && !rule.pattern.test(form[fieldName])) {
        errors[fieldName] = rule.message || '格式不正确';
        return false;
      }
    }
    return true;
  };
  
  const validate = (fieldRules) => {
    let isValid = true;
    for (const [fieldName, rules] of Object.entries(fieldRules)) {
      if (!validateField(fieldName, rules)) {
        isValid = false;
      }
    }
    return isValid;
  };
  
  const reset = () => {
    Object.assign(form, initialValues);
    Object.keys(errors).forEach(key => delete errors[key]);
  };
  
  const isValid = computed(() => {
    return Object.keys(errors).length === 0;
  });
  
  return {
    form,
    errors,
    validateField,
    validate,
    reset,
    isValid
  };
}

// 使用
import { useForm } from './useForm';

export default {
  setup() {
    const { form, errors, validate } = useForm({
      email: '',
      password: ''
    });
    
    const rules = {
      email: [
        { required: true, message: '邮箱必填' },
        { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '请输入有效邮箱' }
      ],
      password: [
        { required: true, message: '密码必填' },
        { pattern: /.{6,}/, message: '密码至少6位' }
      ]
    };
    
    const handleSubmit = () => {
      if (validate(rules)) {
        console.log('Form submitted:', form);
      }
    };
    
    return { form, errors, handleSubmit };
  }
};

高级技巧

依赖注入

javascript 复制代码
// 父组件提供数据
import { provide } from 'vue';

export default {
  setup() {
    const theme = ref('dark');
    
    provide('theme', theme);
    provide('toggleTheme', () => {
      theme.value = theme.value === 'dark' ? 'light' : 'dark';
    });
  }
};

// 子组件注入数据
import { inject } from 'vue';

export default {
  setup() {
    const theme = inject('theme');
    const toggleTheme = inject('toggleTheme');
    
    return { theme, toggleTheme };
  }
};

生命周期钩子

javascript 复制代码
import { onMounted, onUnmounted, onUpdated, onBeforeMount, onBeforeUpdate, onBeforeUnmount } from 'vue';

export default {
  setup() {
    onBeforeMount(() => {
      console.log('组件挂载前');
    });
    
    onMounted(() => {
      console.log('组件挂载完成');
    });
    
    onBeforeUpdate(() => {
      console.log('组件更新前');
    });
    
    onUpdated(() => {
      console.log('组件更新完成');
    });
    
    onBeforeUnmount(() => {
      console.log('组件卸载前');
    });
    
    onUnmounted(() => {
      console.log('组件卸载完成');
    });
  }
};

总结

Vue3的组合式API带来了很多好处:

  1. 更好的代码组织 - 按功能组织代码
  2. 更好的代码复用 - 通过组合式函数复用逻辑
  3. 更好的类型推断 - 更好的TypeScript支持
  4. 更小的打包体积 - 按需导入

技术应当有温度,好的代码结构能提升开发体验。

相关推荐
Shockang21 小时前
AI 智能体安全沙盒实战
人工智能
yuhulkjv3351 天前
Claude表格复制到word不再崩溃,AI导出鸭批量导出+格式无损一键搞定
人工智能·ai·c#·word·ai导出鸭
大明者省1 天前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
抱抱宝1 天前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
抱抱宝1 天前
大模型应用开发教程08 | 构建完整 RAG 应用(Chroma/FAISS 实战)
人工智能·gpt·prompt·agent
美团技术团队1 天前
KDD‘26 美团学术论文精选及KDD Cup‘26 DataAgents赛道冠军思路解读
人工智能
AKAMAI1 天前
当AI模型超出存储增长时
人工智能·云计算
科技绘图1 天前
快鲸GEO vs 传统AI搜索优化:全链路自动化与高效内容生产在转化闭环上的对比
数据库·人工智能·自动化
DS随心转小程序1 天前
ChatGPT 文字怎么转为 word?解析各类转换方案,AI 导出鸭成为高效文档转换新选择
人工智能·chatgpt·word·豆包·deepseek·ai导出鸭
乌恩大侠1 天前
【AI-RAN】硬件产品:DELL 前传交换机
人工智能·spark·aerial·o-ru·ai-ran