Vue基础教程(127)组件和组合API之Vue.js 3.0的新变化1——组合:Vue 3.0 组合API:告别“意大利面代码”,像搭乐高一样写网页!

一、Vue 2的痛:谁没在datamethods之间迷过路?

还记得那些年,我们写Vue 2组件时的场景吗?

export default {
  data() {
    return {
      count: 0,
      message: 'Hello',
      user: { name: '张三', age: 18 }
    }
  },
  methods: {
    increment() { this.count++ },
    showMessage() { console.log(this.message) },
    updateUser() { /* 翻半天找到user在哪 */ }
  },
  mounted() {
    // 这里又想用data里的变量,又想调methods里的方法...
  }
}

这种Options API的写法,就像把衣服、鞋子、零食全扔进一个衣柜——找东西全靠缘分!相关逻辑被强行拆散到不同选项里,组件一复杂,代码就乱成“意大利面”。

二、Vue 3 组合API:给你的代码做个“整理收纳”

Vue 3的组合API(Composition API)核心思想就一句话:把相关的逻辑放一起!

想象一下,你要做个计数器功能:

  • 数据:count
  • 方法:incrementdecrement
  • 生命周期:组件挂载时从本地存储读取初始值

在Vue 2里,这些要分散在datamethodsmounted里。而在Vue 3中,你可以这样:

import { ref, onMounted } from 'vue'

// 把计数器相关的所有逻辑封装到一个函数里
function useCounter() {
  const count = ref(0)
  
  function increment() { count.value++ }
  function decrement() { count.value-- }
  
  onMounted(() => {
    const saved = localStorage.getItem('count')
    if (saved) count.value = parseInt(saved)
  })
  
  // 返回所有需要暴露的东西
  return { count, increment, decrement }
}

这就叫组合函数——把零散的逻辑打包成独立的、可复用的单元!

三、实战:用组合API重构用户管理功能

假设我们要做一个用户列表,支持添加、删除、搜索。看看组合API如何让代码更清晰:

<template>
  <div>
    <input v-model="searchKeyword" placeholder="搜索用户">
    <button @click="addUser">添加随机用户</button>
    
    <ul>
      <li v-for="user in filteredUsers" :key="user.id">
        {{ user.name }}
        <button @click="removeUser(user.id)">删除</button>
      </li>
    </ul>
    
    <p>用户总数:{{ userStats.total }}</p>
    <p>男性用户:{{ userStats.maleCount }}</p>
  </div>
</template>
<script>
import { ref, computed, onMounted } from 'vue'

// 用户数据逻辑
function useUsers() {
  const users = ref([])
  
  const addUser = () => {
    const newUser = {
      id: Date.now(),
      name: `用户${users.value.length + 1}`,
      gender: Math.random() > 0.5 ? 'male' : 'female'
    }
    users.value.push(newUser)
  }
  
  const removeUser = (id) => {
    users.value = users.value.filter(user => user.id !== id)
  }
  
  // 模拟初始化数据
  onMounted(() => {
    users.value = [
      { id: 1, name: '张三', gender: 'male' },
      { id: 2, name: '李四', gender: 'female' }
    ]
  })
  
  return { users, addUser, removeUser }
}

// 用户统计逻辑
function useUserStats(users) {
  const userStats = computed(() => {
    const total = users.value.length
    const maleCount = users.value.filter(u => u.gender === 'male').length
    return { total, maleCount }
  })
  
  return { userStats }
}

// 搜索逻辑
function useSearch(users) {
  const searchKeyword = ref('')
  
  const filteredUsers = computed(() => {
    if (!searchKeyword.value) return users.value
    return users.value.filter(user => 
      user.name.includes(searchKeyword.value)
    )
  })
  
  return { searchKeyword, filteredUsers }
}

export default {
  setup() {
    const { users, addUser, removeUser } = useUsers()
    const { userStats } = useUserStats(users)
    const { searchKeyword, filteredUsers } = useSearch(users)
    
    return {
      users: filteredUsers, // 使用过滤后的用户列表
      addUser,
      removeUser,
      searchKeyword,
      userStats
    }
  }
}
</script>

看到魔法了吗?我们把一个复杂功能拆成了三个独立的逻辑块:

  • useUsers:管理用户数据
  • useUserStats:计算用户统计
  • useSearch:处理搜索过滤

每个函数只关心自己的事情,这就是单一职责原则的完美体现!

四、组合API的超级技能:超越mixin的代码复用

Vue 2里我们常用mixin复用代码,但mixin有很多问题:

  • 命名冲突:多个mixin可能定义相同的属性名
  • 来源不明:一个组件用了多个mixin后,很难知道某个方法来自哪个mixin
  • 关系复杂:mixin之间可能相互依赖

组合API完美解决了这些问题:

// 复用鼠标位置跟踪功能
function useMouse() {
  const x = ref(0)
  const y = ref(0)
  
  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }
  
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))
  
  return { x, y }
}

// 复用本地存储功能
function useLocalStorage(key, initialValue) {
  const data = ref(initialValue)
  
  // 读取已有值
  const stored = localStorage.getItem(key)
  if (stored) data.value = JSON.parse(stored)
  
  // 自动保存
  watch(data, (newValue) => {
    localStorage.setItem(key, JSON.stringify(newValue))
  }, { deep: true })
  
  return data
}

// 在组件中使用
export default {
  setup() {
    const { x, y } = useMouse()
    const settings = useLocalStorage('settings', { theme: 'light' })
    
    return { x, y, settings }
  }
}

这种复用方式清晰明了:你知道每个数据来自哪个函数,命名冲突可以通过重命名解决,TypeScript支持也更好。

五、组合API的进阶玩法:让代码更优雅

1. 响应式状态管理

import { reactive, toRefs } from 'vue'

function useForm() {
  const state = reactive({
    username: '',
    password: '',
    errors: {}
  })
  
  function validate() {
    state.errors = {}
    if (!state.username) state.errors.username = '用户名不能为空'
    if (state.password.length < 6) state.errors.password = '密码太短'
  }
  
  // 使用toRefs保持响应式
  return { ...toRefs(state), validate }
}

2. 异步操作处理

function useApi(endpoint) {
  const data = ref(null)
  const loading = ref(false)
  const error = ref(null)
  
  async function fetchData() {
    loading.value = true
    error.value = null
    try {
      const response = await fetch(endpoint)
      data.value = await response.json()
    } catch (err) {
      error.value = err.message
    } finally {
      loading.value = false
    }
  }
  
  onMounted(fetchData)
  
  return { data, loading, error, refetch: fetchData }
}

六、迁移指南:从Vue 2平稳过渡

如果你有Vue 2项目,别急着重写!可以这样逐步迁移:

  1. 混合使用:Vue 3支持同时使用Options API和Composition API
  2. 从新功能开始:在新功能或重构时尝试组合API
  3. 使用工具:Vue官方提供了迁移工具和兼容版本
// 渐进式迁移示例
export default {
  // 旧的Options API
  data() {
    return { oldData: '我还在' }
  },
  methods: {
    oldMethod() { console.log('老方法') }
  },
  
  // 新的Composition API
  setup() {
    const { newData, newMethod } = useNewFeature()
    
    return { newData, newMethod }
  }
}

七、总结:为什么组合API是未来?

组合API不是要完全取代Options API,而是提供了更好的代码组织方式:

  • 逻辑复用:像搭积木一样组合功能
  • 类型推导:TypeScript支持杠杠的
  • 代码组织:相关代码在一起,维护更轻松
  • 灵活性:不受组件结构限制,自由组合

就像从整理杂乱的衣柜变成使用分类收纳盒,一开始可能需要适应,但一旦习惯,就再也回不去了!

最后的小贴士:组合API的学习曲线确实比Options API陡峭,但投入时间绝对值得。建议从小功能开始尝试,慢慢体会它的美妙之处。记住,好的代码不是写出来的,是“组合”出来的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值