阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Composition API高级用法

Composition API高级用法

作者:陈川 阅读数:46278人阅读 分类: Vue.js

组合式API的核心概念

组合式API是Vue 3引入的全新编程范式,它通过函数式的方式组织组件逻辑。与选项式API不同,组合式API将相关代码组织在一起,而不是分散在不同的选项块中。

import { ref, computed } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)
    
    function increment() {
      count.value++
    }
    
    return {
      count,
      double,
      increment
    }
  }
}

响应式状态管理

ref与reactive的深度使用

refreactive是创建响应式数据的两种主要方式。ref适用于基本类型和对象引用,而reactive专门用于对象。

import { ref, reactive } from 'vue'

const user = reactive({
  name: '张三',
  age: 25,
  address: {
    city: '北京',
    street: '朝阳区'
  }
})

const counter = ref(0)

// 访问ref值需要.value
console.log(counter.value) // 0

// reactive对象可以直接访问
console.log(user.name) // 张三

响应式工具函数

Vue提供了一系列工具函数来处理响应式数据:

import { isRef, unref, toRef, toRefs } from 'vue'

const count = ref(0)
console.log(isRef(count)) // true

// unref自动解包ref
function useValue(maybeRef) {
  return unref(maybeRef)
}

// 将reactive对象的属性转换为ref
const userRef = toRef(user, 'name')

// 将reactive对象的所有属性转换为ref
const { name, age } = toRefs(user)

组合式函数

组合式函数是组合式API的核心抽象机制,它允许我们将可复用的逻辑提取到单独的函数中。

创建自定义组合式函数

// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)
  
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }
  
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))
  
  return { x, y }
}

// 在组件中使用
import { useMouse } from './useMouse'

export default {
  setup() {
    const { x, y } = useMouse()
    return { x, y }
  }
}

带参数的组合式函数

// useFetch.js
import { ref } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(false)
  
  async function fetchData() {
    loading.value = true
    try {
      const response = await fetch(url)
      data.value = await response.json()
    } catch (err) {
      error.value = err
    } finally {
      loading.value = false
    }
  }
  
  fetchData()
  
  return { data, error, loading, retry: fetchData }
}

生命周期钩子的高级用法

组合式API提供了更灵活的生命周期管理方式:

import { onMounted, onUpdated, onUnmounted } from 'vue'

export default {
  setup() {
    onMounted(() => {
      console.log('组件挂载')
    })
    
    onUpdated(() => {
      console.log('组件更新')
    })
    
    onUnmounted(() => {
      console.log('组件卸载')
    })
  }
}

多个同名钩子

组合式API允许注册多个同名生命周期钩子,它们将按注册顺序依次调用:

setup() {
  onMounted(() => console.log('第一个挂载钩子'))
  onMounted(() => console.log('第二个挂载钩子'))
}

依赖注入的深度使用

provideinject可以实现跨层级组件通信:

// 祖先组件
import { provide, ref } from 'vue'

export default {
  setup() {
    const theme = ref('dark')
    
    provide('theme', theme)
    
    return {
      theme
    }
  }
}

// 后代组件
import { inject } from 'vue'

export default {
  setup() {
    const theme = inject('theme', 'light') // 默认值'light'
    
    return {
      theme
    }
  }
}

响应式注入

// 提供响应式值
const counter = ref(0)
provide('counter', counter)

// 注入并保持响应性
const injectedCounter = inject('counter')

模板引用与组件引用

组合式API中通过ref获取DOM元素或组件实例:

import { ref, onMounted } from 'vue'

export default {
  setup() {
    const inputRef = ref(null)
    
    onMounted(() => {
      inputRef.value.focus()
    })
    
    return {
      inputRef
    }
  },
  template: `<input ref="inputRef">`
}

组件方法暴露

子组件可以通过expose明确暴露哪些方法:

// 子组件
import { ref } from 'vue'

export default {
  setup(props, { expose) {
    const count = ref(0)
    
    function increment() {
      count.value++
    }
    
    expose({
      increment
    })
    
    return {
      count
    }
  }
}

// 父组件
const childRef = ref(null)

function callChildMethod() {
  childRef.value.increment()
}

渲染函数与JSX

组合式API中可以直接使用渲染函数:

import { h, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    
    return () => h('div', [
      h('button', {
        onClick: () => count.value++
      }, '增加'),
      h('span', `当前计数: ${count.value}`)
    ])
  }
}

JSX支持

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    
    return () => (
      <div>
        <button onClick={() => count.value++}>增加</button>
        <span>当前计数: {count.value}</span>
      </div>
    )
  }
}

自定义指令

组合式API中创建自定义指令:

import { directive } from 'vue'

const vFocus = {
  mounted(el) {
    el.focus()
  }
}

// 使用
export default {
  directives: {
    focus: vFocus
  },
  setup() {
    return {}
  }
}

全局指令

// main.js
import { createApp } from 'vue'

const app = createApp(App)

app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

性能优化技巧

计算属性的缓存

import { computed, ref } from 'vue'

export default {
  setup() {
    const firstName = ref('张')
    const lastName = ref('三')
    
    const fullName = computed(() => `${firstName.value}${lastName.value}`)
    
    return {
      fullName
    }
  }
}

防抖与节流

import { ref } from 'vue'
import { debounce } from 'lodash-es'

export default {
  setup() {
    const searchQuery = ref('')
    
    const debouncedSearch = debounce(() => {
      console.log('搜索:', searchQuery.value)
    }, 500)
    
    function onInput() {
      debouncedSearch()
    }
    
    return {
      searchQuery,
      onInput
    }
  }
}

TypeScript集成

组合式API与TypeScript有很好的集成:

import { ref, computed } from 'vue'

interface User {
  name: string
  age: number
}

export default {
  setup() {
    const user = ref<User>({
      name: '张三',
      age: 25
    })
    
    const nextYearAge = computed(() => user.value.age + 1)
    
    return {
      user,
      nextYearAge
    }
  }
}

类型推断

import { ref } from 'vue'

const count = ref(0) // 推断为Ref<number>

count.value = '1' // 类型错误

状态管理集成

组合式API可以轻松集成Pinia等状态管理库:

// store/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  }
})

// 组件中使用
import { useCounterStore } from '@/stores/counter'

export default {
  setup() {
    const counter = useCounterStore()
    
    return {
      counter
    }
  }
}

异步组件与Suspense

组合式API支持异步组件:

import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/AsyncComponent.vue')
)

export default {
  components: {
    AsyncComp
  },
  setup() {
    return {}
  }
}

Suspense集成

<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

<script>
import { defineAsyncComponent } from 'vue'

export default {
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./AsyncComponent.vue')
    )
  }
}
</script>

自定义组合式API库

将多个组合式函数组织成库:

// composables/index.js
export * from './useMouse'
export * from './useFetch'
export * from './useLocalStorage'

// 组件中使用
import { useMouse, useFetch } from '@/composables'

export default {
  setup() {
    const { x, y } = useMouse()
    const { data } = useFetch('/api/data')
    
    return {
      x,
      y,
      data
    }
  }
}

响应式CSS变量

组合式API可以动态生成CSS变量:

import { ref, watchEffect } from 'vue'

export default {
  setup() {
    const themeColor = ref('#42b983')
    
    watchEffect(() => {
      document.documentElement.style.setProperty(
        '--theme-color',
        themeColor.value
      )
    })
    
    return {
      themeColor
    }
  }
}

服务端渲染(SSR)支持

组合式API在SSR环境下的特殊处理:

import { ref, onServerPrefetch } from 'vue'
import { fetchData } from './api'

export default {
  setup() {
    const data = ref(null)
    
    onServerPrefetch(async () => {
      data.value = await fetchData()
    })
    
    return {
      data
    }
  }
}

调试技巧

组合式API提供了调试工具:

import { debug } from 'vue'

export default {
  setup() {
    const count = ref(0)
    
    debug(count) // 在控制台输出响应式数据的变化
    
    return {
      count
    }
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:热模块替换支持

下一篇:自定义hook开发

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌