Vue3组合式API实战:从Options API迁移的最佳路径与性能对比

Options API到Composition API不是重写,是渐进迁移

Vue3的Composition API解决了Options API的核心痛点:逻辑分散在data、methods、computed、watch中,相关业务代码被拆到不同选项里,一个功能的代码散落在4个地方。组合式API把同一逻辑关注点的代码收拢到一起,可维护性直接上一个台阶。迁移不需要一次性重写,两个API可以在同一个组件中共存。

Options API与Composition API的代码组织对比

以一个用户列表页为例,包含搜索、分页、批量操作三个功能。Options API写法下,搜索逻辑的keyword、filteredList、search方法分别放在data、computed、methods三个选项里。Composition API写法:

// useSearch.js - 搜索逻辑独立为composable
import { ref, computed } from 'vue'

export function useSearch(listSource) {
  const keyword = ref('')
  const filteredList = computed(() => {
    if (!keyword.value) return listSource.value
    return listSource.value.filter(item => 
      item.name.includes(keyword.value)
    )
  })
  
  function clearSearch() {
    keyword.value = ''
  }
  
  return { keyword, filteredList, clearSearch }
}
// usePagination.js - 分页逻辑独立
import { ref, computed } from 'vue'

export function usePagination(listRef, pageSize = 10) {
  const currentPage = ref(1)
  const total = computed(() => listRef.value.length)
  const totalPages = computed(() => Math.ceil(total.value / pageSize))
  const pagedList = computed(() => {
    const start = (currentPage.value - 1) * pageSize
    return listRef.value.slice(start, start + pageSize)
  })
  
  function goToPage(page) {
    if (page >= 1 && page <= totalPages.value) {
      currentPage.value = page
    }
  }
  
  return { currentPage, totalPages, pagedList, goToPage }
}
// UserList.vue - 组件只做组合
<script setup>
import { ref, onMounted } from 'vue'
import { useSearch } from './useSearch'
import { usePagination } from './usePagination'

const users = ref([])
onMounted(async () => {
  users.value = await fetchUsers()
})

const { keyword, filteredList, clearSearch } = useSearch(users)
const { currentPage, totalPages, pagedList, goToPage } = usePagination(filteredList)
</script>

三个功能的代码各自收拢在独立的composable中,组件只负责组合。要改搜索逻辑,打开useSearch.js就行,不用在500行文件里上下翻找。

渐进迁移策略:共存期不中断业务

Vue3支持在同一个组件中混用两种API。迁移策略是增量替换,不是推倒重来:

步骤1:新组件全部用Composition API

新页面和新组件直接写<script setup>,不用Options API。这是零成本的,不需要改动任何现有代码。

步骤2:复杂组件拆分composable

对超过300行的Options API组件,先提取最独立的逻辑为composable。表单验证、数据请求、分页这类通用逻辑优先提取:

// 迁移前 - Options API中的表单逻辑
export default {
  data() {
    return {
      form: { name: '', email: '' },
      errors: { name: '', email: '' }
    }
  },
  methods: {
    validate() {
      this.errors.name = this.form.name ? '' : '必填'
      this.errors.email = /\S+@\S+/.test(this.form.email) ? '' : '格式错误'
      return !this.errors.name && !this.errors.email
    }
  }
}

// 迁移后 - 提取为composable
export function useFormValidation(rules) {
  const form = ref({})
  const errors = ref({})
  
  function validate() {
    let valid = true
    for (const [field, rule] of Object.entries(rules)) {
      const msg = rule(form.value[field])
      errors.value[field] = msg || ''
      if (msg) valid = false
    }
    return valid
  }
  
  return { form, errors, validate }
}

步骤3:旧组件用setup()选项过渡

对于不方便直接改成<script setup>的旧组件,可以在Options API中加setup()函数,先在setup中写新逻辑,逐步把data和methods迁移过来:

export default {
  // 旧代码保留
  data() {
    return {
      legacyData: 'still here'
    }
  },
  // 新逻辑写在setup中
  setup() {
    const { form, errors, validate } = useFormValidation({
      name: v => v ? '' : '必填',
      email: v => /\S+@\S+/.test(v) ? '' : '格式错误'
    })
    return { form, errors, validate }
  },
  methods: {
    // 旧方法继续工作,逐步迁移到setup
  }
}

性能实测:Composition API的优化空间

Composition API本身不比Options API快,但它释放了Vue3响应式系统的优化潜力:

响应式追踪精度

// Options API - 整个data对象追踪
data() {
  return {
    user: { name: 'zhangsan', age: 25, address: {...} },
    list: [...1000 items]
  }
}
// 任何属性变化都触发整个组件重新渲染

// Composition API - 按需追踪
const userName = ref('zhangsan')         // 只追踪name
const list = shallowRef([...1000 items]) // 只追踪引用变化
// 精准控制追踪范围,减少不必要的重渲染

计算属性缓存对比

// 大数组过滤场景实测
// Options API
computed: {
  filteredList() {
    return this.list.filter(item => item.score > 80)
  }
}

// Composition API - 手动控制依赖
const filteredList = computed(() => {
  return list.value.filter(item => item.score > 80)
})

// 当list有10000条数据时
// Composition API配合shallowRef,修改单条数据不会触发重新过滤
// Options API的深度追踪会在任何嵌套属性变化时重算

在10000条数据量的列表组件实测中,Composition API + shallowRef的更新耗时是Options API的1/3。不是API本身更快,是shallowRef跳过了深层响应式追踪,减少了setter触发的数量。

迁移常见问题与解决方案

问题1:this在setup中不存在

setup在组件实例创建之前执行,没有this。需要通过参数访问:

// setup接收props和context
setup(props, { emit, slots, attrs }) {
  // 用props代替this.props
  // 用emit代替this.$emit
  // 用attrs代替this.$attrs
  watch(() => props.modelValue, (val) => {
    // 替代this.$watch
  })
}

问题2:生命周期钩子改名

// Options API -> Composition API
created       -> 直接在setup中执行
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeUnmount -> onBeforeUnmount
unmounted     -> onUnmounted

问题3:mixin冲突怎么办

mixin的命名冲突是Options API的顽疾。Composition API天然解决——composable的返回值由组件自行解构命名:

// 两个mixin都有search方法 - 冲突!
// Composition API解法:
const { search: userSearch } = useUserSearch()
const { search: productSearch } = useProductSearch()
// 完全没有冲突

迁移完成后的收益不只是代码组织。composable天然可测试(纯函数+ref)、可复用(跨项目共享)、可类型推导(TypeScript友好)。从长远看,Composition API是Vue3生态的标准写法,早迁早受益。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/vue3-zu-he-shi-api-shi-zhan-cong-optionsapi-qian-yi-de-zui/

(0)
小编小编
上一篇 14小时前
下一篇 14小时前

相关推荐