Skip to content

Vue 2.7 使用 Composition API


安装配置

1. 安装依赖

bash
npm install @vue/composition-api
# 或
yarn add @vue/composition-api

2. 注册插件

javascript
// main.js
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)

基础用法

1. 基本结构

vue
<template>
  <div>{{ count }}</div>
</template>

<script>
import { defineComponent, ref } from '@vue/composition-api'

export default defineComponent({
  setup() {
    const count = ref(0)
    
    return {
      count
    }
  }
})
</script>

2. 响应式引用

javascript
import { ref, reactive } from '@vue/composition-api'

// ref 用于基本类型
const count = ref(0)
console.log(count.value) // 获取值需要使用 .value

// reactive 用于对象
const state = reactive({
  name: '张三',
  age: 18
})
console.log(state.name) // 直接访问属性

3. 计算属性

javascript
import { ref, computed } from '@vue/composition-api'

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

// 可写的计算属性
const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (val) => {
    [firstName.value, lastName.value] = val.split(' ')
  }
})

4. 监听器

javascript
import { ref, watch, watchEffect } from '@vue/composition-api'

const count = ref(0)

// 基础监听
watch(count, (newVal, oldVal) => {
  console.log('count changed:', newVal, oldVal)
})

// 监听多个数据源
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
  console.log('values changed')
})

// 立即执行的监听器
watchEffect(() => {
  console.log('count is:', count.value)
})

5. 生命周期钩子

javascript
import {
  onMounted,
  onBeforeMount,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured
} from '@vue/composition-api'

export default defineComponent({
  setup() {
    onBeforeMount(() => {
      console.log('before mount')
    })
    
    onMounted(() => {
      console.log('mounted')
    })
    
    // 其他生命周期钩子...
  }
})

6. Props 和 Context

javascript
export default defineComponent({
  props: {
    title: String
  },
  setup(props, context) {
    // props 是响应式的
    console.log(props.title)
    
    // context 包含 attrs, slots, emit
    const { attrs, slots, emit } = context
    
    // 触发事件
    const handleClick = () => {
      emit('custom-event', 'some data')
    }
    
    return {
      handleClick
    }
  }
})

7. 提取复用逻辑(组合函数)

javascript
// useCounter.js
import { ref } from '@vue/composition-api'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  const increment = () => {
    count.value++
  }
  
  const decrement = () => {
    count.value--
  }
  
  return {
    count,
    increment,
    decrement
  }
}

// 使用组合函数
import { useCounter } from './useCounter'

export default defineComponent({
  setup() {
    const { count, increment, decrement } = useCounter(10)
    
    return {
      count,
      increment,
      decrement
    }
  }
})

8. 获取组件实例

javascript
import { getCurrentInstance } from '@vue/composition-api'

export default defineComponent({
  setup() {
    const { proxy } = getCurrentInstance()
    // proxy 等同于 this
    console.log(proxy.$router)
  }
})

注意事项

  1. setup 函数在组件创建之前被调用,此时组件实例还未创建
  2. setup 中不能使用 this
  3. ref 包装的值需要通过 .value 访问
  4. 返回的对象中的属性会暴露给模板使用
  5. 生命周期钩子需要在 setup 内同步调用

最佳实践

  1. 使用 defineComponent 获得更好的 TypeScript 支持
  2. 复杂的状态管理推荐使用 reactive
  3. 简单的值使用 ref
  4. 提取可复用的逻辑到组合函数中
  5. 保持 setup 函数简洁,将复杂逻辑拆分到组合函数

TypeScript 支持

typescript
import { defineComponent, PropType } from '@vue/composition-api'

interface User {
  name: string
  age: number
}

export default defineComponent({
  props: {
    user: {
      type: Object as PropType<User>,
      required: true
    }
  },
  setup(props) {
    // props.user 将有完整的类型提示
  }
})

Released under the MIT License.