Vue 3 推荐选择组合式 API 风格(附录与选项式的代码对比)

Vue3 选项式 API vs 组合式 API 选择指南

Vue 的组件可以按两种不同的风格书写选项式 API组合式 API

两种风格的核心区别

选项式 API (Options API) ------ 类似面向对象封装

vue 复制代码
<script>
export default {
  // 选项分离
  data() {
    return {
      count: 0,
      message: 'Hello'
    }
  },
  computed: {
    doubleCount() {
      return this.count * 2
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  watch: {
    count(newVal) {
      console.log('count changed:', newVal)
    }
  },
  mounted() {
    console.log('组件已挂载')
  }
}
</script>

组合式 API (Composition API) ------ 类似函数式编程

vue 复制代码
<script setup>
import { ref, computed, watch, onMounted } from 'vue'

// 逻辑聚合
const count = ref(0)
const message = ref('Hello')

const doubleCount = computed(() => count.value * 2)

const increment = () => {
  count.value++
}

watch(count, (newVal) => {
  console.log('count changed:', newVal)
})

onMounted(() => {
  console.log('组件已挂载')
})
</script>

选择决策树

markdown 复制代码
选择哪种 API?
│
├── 你是 Vue 初学者?且习惯面向对象编程
│   ├── 是 → 选项式 API (更容易理解)
│   └── 否 → 继续下面的选择
│
├── 项目复杂度如何?
│   ├── 简单组件 → 任选其一
│   ├── 复杂组件 → 组合式 API
│   └── 大型项目 → 组合式 API
│
├── 团队经验如何?
│   ├── 都熟悉 Composition API → 组合式 API
│   ├── 有 React 经验 → 组合式 API
│   └── 传统前端背景 → 选项式 API
│
└── 需要逻辑复用?
    ├── 是 → 组合式 API
    └── 否 → 任选其一

详细对比分析

1. 学习曲线对比

初学者友好度
javascript 复制代码
// 选项式 API - 更符合传统面向对象思维
export default {
  data() {
    return {
      // 数据都在这里,一目了然
      users: [],
      loading: false,
      error: null
    }
  },
  methods: {
    // 方法都在这里,逻辑清晰
    async fetchUsers() {
      this.loading = true
      try {
        this.users = await api.getUsers()
      } catch (err) {
        this.error = err.message
      } finally {
        this.loading = false
      }
    }
  }
}

// 组合式 API - 需要理解响应式系统
import { ref } from 'vue'

export default {
  setup() {
    // 需要理解 ref、reactive 等概念
    const users = ref([])
    const loading = ref(false)
    const error = ref(null)
    
    const fetchUsers = async () => {
      loading.value = true  // 注意要 .value
      try {
        users.value = await api.getUsers()  // 注意要 .value
      } catch (err) {
        error.value = err.message  // 注意要 .value
      } finally {
        loading.value = false  // 注意要 .value
      }
    }
    
    return {
      users,
      loading,
      error,
      fetchUsers
    }
  }
}

2. 逻辑组织对比

复杂组件中的逻辑组织
vue 复制代码
<!-- 选项式 API - 相关逻辑被分散 -->
<script>
export default {
  data() {
    return {
      // 用户相关数据
      userName: '',
      userEmail: '',
      userAge: 0,
      
      // 产品相关数据
      productName: '',
      productPrice: 0,
      productCategory: ''
    }
  },
  computed: {
    // 用户相关计算属性
    userDisplayName() {
      return this.userName || this.userEmail
    },
    userAgeGroup() {
      return this.userAge >= 18 ? '成人' : '未成年'
    },
    
    // 产品相关计算属性
    productDiscount() {
      return this.productPrice > 100 ? this.productPrice * 0.9 : this.productPrice
    }
  },
  methods: {
    // 用户相关方法
    validateUser() { /* ... */ },
    saveUser() { /* ... */ },
    
    // 产品相关方法
    validateProduct() { /* ... */ },
    saveProduct() { /* ... */ }
  },
  watch: {
    // 用户相关监听
    userName() { /* ... */ },
    userEmail() { /* ... */ },
    
    // 产品相关监听
    productName() { /* ... */ },
    productPrice() { /* ... */ }
  }
}
</script>
vue 复制代码
<!-- 组合式 API - 相关逻辑可以聚合 -->
<script setup>
// 用户相关逻辑聚合在一起
const {
  userName,
  userEmail,
  userAge,
  userDisplayName,
  userAgeGroup,
  validateUser,
  saveUser
} = useUser()

// 产品相关逻辑聚合在一起
const {
  productName,
  productPrice,
  productCategory,
  productDiscount,
  validateProduct,
  saveProduct
} = useProduct()
</script>

3. 逻辑复用对比

选项式 API 的 Mixin 方式(已不推荐)
javascript 复制代码
// userMixin.js
export const userMixin = {
  data() {
    return {
      userName: '',
      userEmail: ''
    }
  },
  methods: {
    validateUser() {
      return this.userName && this.userEmail
    }
  }
}

// ProductMixin.js
export const productMixin = {
  data() {
    return {
      productName: '',
      productPrice: 0
    }
  },
  methods: {
    validateProduct() {
      return this.productName && this.productPrice > 0
    }
  }
}

// 组件中使用
export default {
  mixins: [userMixin, productMixin],
  // 命名冲突风险,数据来源不清晰
}
组合式 API 的 Composable 方式(推荐)
javascript 复制代码
// composables/useUser.js
import { ref, computed } from 'vue'

export function useUser() {
  const userName = ref('')
  const userEmail = ref('')
  
  const userDisplayName = computed(() => userName.value || userEmail.value)
  
  const validateUser = () => {
    return userName.value && userEmail.value
  }
  
  const saveUser = async () => {
    // 保存逻辑
  }
  
  return {
    userName,
    userEmail,
    userDisplayName,
    validateUser,
    saveUser
  }
}

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

export function useProduct() {
  const productName = ref('')
  const productPrice = ref(0)
  
  const productDiscount = computed(() => 
    productPrice.value > 100 ? productPrice.value * 0.9 : productPrice.value
  )
  
  const validateProduct = () => {
    return productName.value && productPrice.value > 0
  }
  
  return {
    productName,
    productPrice,
    productDiscount,
    validateProduct
  }
}

// 组件中使用
<script setup>
import { useUser, useProduct } from '@/composables'

const { userName, userEmail, validateUser } = useUser()
const { productName, productPrice, validateProduct } = useProduct()
</script>

具体场景选择建议

1. 项目阶段选择

新手学习阶段
javascript 复制代码
// 推荐:选项式 API
// 理由:概念清晰,学习曲线平缓
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
项目重构阶段
javascript 复制代码
// 推荐:逐步迁移
// 理由:可以渐进式升级,降低风险

// 旧组件保持选项式 API
// 新组件使用组合式 API
// 两者可以共存

2. 团队背景选择

传统前端团队
javascript 复制代码
// 推荐:选项式 API
// 团队成员更容易上手和维护

export default {
  name: 'UserManagement',
  data() {
    return {
      users: [],
      loading: false,
      searchKeyword: ''
    }
  },
  computed: {
    filteredUsers() {
      return this.users.filter(user => 
        user.name.includes(this.searchKeyword)
      )
    }
  },
  methods: {
    async loadUsers() {
      this.loading = true
      try {
        this.users = await userService.getUsers()
      } finally {
        this.loading = false
      }
    }
  }
}
现代前端团队
javascript 复制代码
// 推荐:组合式 API
// 更好的逻辑复用和维护性

// composables/useUserManagement.js
export function useUserManagement() {
  const users = ref([])
  const loading = ref(false)
  const searchKeyword = ref('')
  
  const filteredUsers = computed(() => 
    users.value.filter(user => 
      user.name.includes(searchKeyword.value)
    )
  )
  
  const loadUsers = async () => {
    loading.value = true
    try {
      users.value = await userService.getUsers()
    } finally {
      loading.value = false
    }
  }
  
  return {
    users,
    loading,
    searchKeyword,
    filteredUsers,
    loadUsers
  }
}

// 组件中使用
<script setup>
import { useUserManagement } from '@/composables'

const { users, loading, searchKeyword, filteredUsers, loadUsers } = useUserManagement()
</script>

3. 功能复杂度选择

简单展示组件
vue 复制代码
<!-- 推荐:任选其一,选项式 API 可能更简洁 -->
<script>
export default {
  props: {
    user: Object
  },
  computed: {
    displayName() {
      return this.user.nickname || this.user.name
    }
  }
}
</script>
复杂业务组件
vue 复制代码
<!-- 推荐:组合式 API -->
<script setup>
// 多个业务逻辑域的聚合
const { 
  // 用户认证相关
  isAuthenticated, 
  login, 
  logout 
} = useAuth()

const { 
  // 表单相关
  formData, 
  errors, 
  validate, 
  submit 
} = useForm()

const { 
  // 数据获取相关
  data, 
  loading, 
  error, 
  refresh 
} = useApi('/api/users')

const { 
  // 权限相关
  hasPermission, 
  checkPermission 
} = usePermission()

// 组合逻辑
const canSubmit = computed(() => 
  isAuthenticated.value && 
  !loading.value && 
  Object.keys(errors.value).length === 0
)
</script>

混合使用策略

Vue3 允许混合使用

vue 复制代码
<script>
// 可以在选项式 API 中使用组合式 API
import { ref, computed } from 'vue'
import { useUser } from '@/composables'

export default {
  data() {
    return {
      localCount: 0
    }
  },
  setup() {
    // 在 setup 中使用组合式 API
    const { userName, userEmail } = useUser()
    const doubleCount = computed(() => this.localCount * 2)  // 注意这里的 this
    
    return {
      userName,
      userEmail,
      doubleCount
    }
  },
  methods: {
    increment() {
      this.localCount++
    }
  }
}
</script>

推荐的混合使用场景

vue 复制代码
<script>
// 在大型项目中,可以这样过渡
import { useUser, useProduct } from '@/composables'

export default {
  // 保留选项式 API 的结构
  data() {
    return {
      // 组件特有的简单状态
      showDialog: false,
      tabActive: 'user'
    }
  },
  setup() {
    // 复杂业务逻辑使用组合式 API
    const userLogic = useUser()
    const productLogic = useProduct()
    
    return {
      ...userLogic,
      ...productLogic
    }
  },
  methods: {
    // 简单的事件处理
    handleTabChange(tab) {
      this.tabActive = tab
    }
  }
}
</script>

最终建议

选择标准总结:

场景 推荐 理由
Vue 初学者 选项式 API 学习曲线平缓,概念清晰
简单组件 任选其一 功能简单,两种方式差异不大
复杂组件 组合式 API 逻辑聚合,易于维护
需要逻辑复用 组合式 API Composable 比 Mixin 更好
大型项目 组合式 API 更好的代码组织和维护性
团队统一 团队决定 保持项目一致性最重要
现有项目 渐进迁移 两种风格可以共存

实践建议:

  1. 新手团队:先用选项式 API 熟悉 Vue 概念
  2. 新项目 :推荐组合式 API + <script setup>
  3. 老项目:可以保持现状,新功能用组合式 API
  4. 团队决策:统一风格比技术选型更重要

记住:没有绝对的好坏,只有适合与否。选择团队最能理解和维护的方式,就是最好的选择!

相关推荐
一枚前端小能手5 分钟前
🎨 用户等不了3秒就跑了,你这时如何是好
前端
Eddy7 分钟前
什么时候应该用useCallback
前端
愿化为明月_随波逐流8 分钟前
关于uniapp开发安卓sdk的aar,用来控制pda的rfid的扫描
前端
探码科技10 分钟前
AI知识管理全面指南:助力企业高效协作与创新
前端
Eddy10 分钟前
react中什么时候应该用usecallback中代码优化
前端
Juchecar19 分钟前
Vue3 应用、组件概念详解 - 初学者完全指南
前端·vue.js
w_y_fan20 分钟前
双token机制:flutter_secure_storage 实现加密存储
前端·flutter
yvvvy21 分钟前
HTTP 从 0.9 到 3.0,一次穿越 30 年的网络进化之旅
前端·javascript
复苏季风1 小时前
聊聊 ?? 运算符:一个懂得 "分寸" 的默认值高手
前端·javascript
探码科技1 小时前
AI驱动的知识库:客户支持与文档工作的新时代
前端