VueUse 组合式工具集

FreeGuideOnline 最新 2026-07-12

VueUse 组合式工具集:从入门到工程化实践

什么是 VueUse?

VueUse 是基于 Vue 3 Composition API 的实用工具函数集合,由开发者 Anthony Fu 创建并维护。它封装了数百个与浏览器 API、状态管理、传感器、动画、时间等相关的组合式函数(Composables),帮助你在 Vue 项目中以声明式、响应式的方式使用原生能力,显著减少样板代码。

核心理念

  • Composition First:所有功能都以 use... 的形式提供,完美融入 setup<script setup> 语法。
  • 按需引入与 Tree‑shaking:只打包你实际用到的函数,零负担接入。
  • 跨平台支持:多数工具同时兼容浏览器、Node.js、Nuxt 等环境(部分通过 @vueuse/integrations 提供扩展)。
  • 类型安全:完整的 TypeScript 支持,类型推导开箱即用。

快速上手

安装

在现有 Vue 3 项目中添加 VueUse:

npm install @vueuse/core

或使用 yarn / pnpm:

yarn add @vueuse/core
pnpm add @vueuse/core

第一个组合式函数:useMouse

useMouse 用于跟踪鼠标在页面中的坐标,它是学习 VueUse 的最佳起点。

<script setup>
import { useMouse } from '@vueuse/core'

const { x, y } = useMouse()
</script>

<template>
  <div>鼠标坐标X {{ x }}, Y {{ y }}</div>
</template>
  • xy 是响应式引用,会在鼠标移动时自动更新。
  • 组件卸载后监听器会自动清理,无需手动 removeEventListener

核心功能分类与典型用法

VueUse 提供了超过 200 个函数,官方文档将其按功能划分为多个类别。以下挑选高频工具进行介绍。

浏览器与传感器

这些函数将浏览器原生 API 转化为响应式数据。

useWindowSize:监听窗口尺寸变化。

<script setup>
import { useWindowSize } from '@vueuse/core'
const { width, height } = useWindowSize()
</script>
<template>
  <p>窗口宽度{{ width }}px高度{{ height }}px</p>
</template>

useGeolocation:获取地理位置。

import { useGeolocation } from '@vueuse/core'
const { coords, locatedAt, error } = useGeolocation()

usePreferredDark:检测系统是否偏好深色主题。

<script setup>
import { usePreferredDark } from '@vueuse/core'
const isDark = usePreferredDark()
</script>
<template>
  <div :class="{ dark: isDark }">自动适应深色模式</div>
</template>

useOnline:检测网络连接状态。

import { useOnline } from '@vueuse/core'
const online = useOnline()

状态与存储

useLocalStorage / useSessionStorage:将响应式数据自动同步到 Web Storage。

import { useLocalStorage } from '@vueuse/core'
// 创建一个与 localStorage 中 `user-settings` 键绑定的 ref
const settings = useLocalStorage('user-settings', { theme: 'auto', fontSize: 14 })
// 修改 settings.value 会自动写入 localStorage
  • 支持对象序列化,可传入自定义 serializer
  • 多标签页同步(监听 storage 事件)。

useStorage:通用存储接口,可适配 sessionStorage、localStorage 或自定义存储。

import { useStorage } from '@vueuse/core'
const token = useStorage('auth-token', null, sessionStorage)

useRefHistory:为任何 ref 添加撤销/重做历史。

import { ref } from 'vue'
import { useRefHistory } from '@vueuse/core'

const text = ref('')
const { undo, redo, canUndo, canRedo, history } = useRefHistory(text)

非常适合文本编辑器、表单草稿等场景。

DOM 与工具函数

onClickOutside:点击元素外部触发回调。

<script setup>
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'

const target = ref(null)
onClickOutside(target, () => { console.log('点击了外部') })
</script>
<template>
  <div ref="target">点击这个 div 的外部试试</div>
</template>

useIntersectionObserver:元素可见性侦测,用于懒加载或无限滚动。

<script setup>
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'

const el = ref(null)
const isVisible = ref(false)

useIntersectionObserver(el, ([{ isIntersecting }]) => {
  isVisible.value = isIntersecting
})
</script>

useVModel:简化 v-model 在自定义组件中的双向绑定。

<!-- 子组件 -->
<script setup>
import { useVModel } from '@vueuse/core'
const props = defineProps({ modelValue: String })
const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)
</script>
<template>
  <input v-model="value" />
</template>

useClipboard:复制文本到剪贴板。

import { useClipboard } from '@vueuse/core'
const { text, copy, copied, isSupported } = useClipboard()
copy('Hello VueUse') // 复制完成后 copied 变为 true

网络请求与异步控制

虽非 axios 替代品,但 VueUse 提供了轻量级的请求管理工具。

useFetch:对 fetch 的响应式封装。

<script setup>
import { useFetch } from '@vueuse/core'
const { data, isFetching, error, execute } = useFetch('https://api.example.com/data').json()
</script>
  • 自动处理请求状态、取消操作。
  • 支持 ref 驱动的 URL,当 URL 变化时自动重新请求。

useAxios(需安装 @vueuse/integrations 和 axios):

import { useAxios } from '@vueuse/integrations/useAxios'
const { data, isLoading } = useAxios('/api/users')

工具与时间

useDebounceFn / useThrottleFn:防抖与节流。

import { useDebounceFn } from '@vueuse/core'
const debouncedSearch = useDebounceFn((query) => {
  // 请求接口
}, 500)

也可以直接使用 refDebounced 来控制 ref 的防抖:

import { refDebounced } from '@vueuse/core'
const input = ref('')
const debounced = refDebounced(input, 300)
watch(debounced, (val) => { /* 搜索逻辑 */ })

useNow:实时更新的当前时间。

<script setup>
import { useNow } from '@vueuse/core'
const now = useNow()
</script>
<template>
  <div>{{ now.toLocaleTimeString() }}</div>
</template>

useIntervalFn:可控制的 setInterval

import { useIntervalFn } from '@vueuse/core'
const { pause, resume, isActive } = useIntervalFn(() => {
  console.log('每秒执行一次')
}, 1000)

工程化配置与注意事项

  1. 按需引入与打包体积 VueUse 支持 Tree‑shaking,只需从 @vueuse/core 导入具体函数,未被使用的代码不会打包。

    import { useMouse, useLocalStorage } from '@vueuse/core'
    

    不建议 import * as VueUse from ...,这会引入整个库。

  2. SSR(服务端渲染)兼容性 VueUse 会自动判断运行环境,若代码在服务端执行,部分浏览器 API 会被安全跳过或返回默认值。你可以在 nuxt.config.ts 中直接使用 @vueuse/nuxt 模块获得更好的 SSR 支持(自动导入等)。

  3. 与 Nuxt 集成 对于 Nuxt 3 项目,推荐安装 @vueuse/nuxt 模块。

    // nuxt.config.ts
    export default defineNuxtConfig({
      modules: ['@vueuse/nuxt'],
    })
    

    此后所有核心 composables 将自动导入,无需手动 import。

  4. 自定义配置 某些函数支持全局配置。例如 useStorage 可设置默认序列化器:

    import { configure } from '@vueuse/core'
    configure({
      storage: { serializer: { read: ..., write: ... } }
    })
    

实战案例:打造一个待办事项应用

整合多个 VueUse 工具,快速构建功能完整的小应用。

需求

  • 添加/删除/编辑待办
  • 数据持久化至 localStorage
  • 撤销/重做操作
  • 实时显示当前时间
  • 点击外部关闭编辑
<script setup>
import { ref } from 'vue'
import { useLocalStorage, useRefHistory, useNow, onClickOutside } from '@vueuse/core'

// 持久化待办列表
const todos = useLocalStorage('vueuse-todos', [])
const { undo, redo, canUndo, canRedo } = useRefHistory(todos, { deep: true })

const newTodo = ref('')
const editingIndex = ref(-1)
const editInput = ref(null)
const now = useNow()

function addTodo() {
  if (!newTodo.value.trim()) return
  todos.value.push({ text: newTodo.value, done: false })
  newTodo.value = ''
}

function removeTodo(index) {
  todos.value.splice(index, 1)
}

function startEdit(index) {
  editingIndex.value = index
  // 下一帧自动聚焦编辑输入
  nextTick(() => editInput.value?.focus())
}

// 点击编辑框外部时退出编辑状态
onClickOutside(editInput, () => { editingIndex.value = -1 })
</script>

<template>
  <div>
    <h2>📝 待办事项</h2>
    <p>当前时间{{ now.toLocaleString() }}</p>
    
    <div>
      <input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加新任务" />
      <button @click="addTodo">添加</button>
    </div>

    <ul>
      <li v-for="(todo, index) in todos" :key="index">
        <input type="checkbox" v-model="todo.done" />
        <span v-if="editingIndex !== index">{{ todo.text }}</span>
        <input v-else ref="editInput" v-model="todo.text" @keyup.enter="editingIndex = -1" />
        <button @click="startEdit(index)">编辑</button>
        <button @click="removeTodo(index)">删除</button>
      </li>
    </ul>

    <div>
      <button :disabled="!canUndo" @click="undo">↩ 撤销</button>
      <button :disabled="!canRedo" @click="redo"> 重做</button>
    </div>
  </div>
</template>

扩展资源与最佳实践

  • 官方文档:vueuse.org 提供了完整的函数列表、在线演示和 TypeScript 声明。
  • VueUse Playground:在文档中可以直接修改示例代码并实时查看效果。
  • @vueuse/components:提供无渲染组件(Renderless Components),如 <UseMouse><UseDark> 等,适用于偏好模板语法的开发者。
  • 最佳实践
    • 将 VueUse 函数视为原子逻辑块,继续在自定义 composables 中组合它们,形成项目专属的业务逻辑层。
    • 利用 effectScopeonScopeDispose 管理副作用清理(VueUse 内部已处理多数清理)。
    • 关注 @vueuse/integrations 提供的 useAxiosuseJwtuseFocusTrap 等与第三方库桥接的函数,避免重复造轮子。

VueUse 不仅是工具集,更是一种“Composition API 思维”的具体展现。熟练运用它将大幅提升你的 Vue 开发效率,让代码更简洁、更健壮。