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.