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. 更小的打包体积 - 按需导入

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

相关推荐
罗西的思考1 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
IT_陈寒2 小时前
SpringBoot自动配置的坑,我的API突然就404了
前端·人工智能·后端
笃行3502 小时前
从零到上线:用 EdgeOne Makers + CodeBuddy 搭一个「对账核对员」AI Agent
人工智能
用户6856326208693 小时前
Claude Code 乱猜字段名?我给它写了一个"数据库查询约束 Skill"
人工智能
你_好3 小时前
# 给你的产品嵌入一个「会操作界面的 AI 助手」
人工智能
ShallWeL3 小时前
【机器学习】(3)—— 线性回归:梯度下降
人工智能·机器学习
陈广亮3 小时前
Prompt、Context、Harness、Agentic:LLM 应用四层嵌套结构,搞清自己卡在哪一层
人工智能
刺猬的温驯3 小时前
Flow Matching 训练的输入分布问题:从 VAE Latent 统计性质到归一化工程实践——以 VoxFlash-TTS 为例
人工智能·语音合成·tts
机器之心3 小时前
近80年后,埃尔德什经典「拉姆齐数下界」,被三位中国学者首次指数级改进
人工智能·openai
机器之心3 小时前
Nvidia都在点赞的LoopWM世界模型,竟然来自一家中国初创FaceMind?
人工智能·openai