name: v3-use-composables description: 项目内置组合式函数使用教程,涵盖设备检测、异步下拉、全屏加载、分页、路由监听、主题切换、动态标题、水印等组合式函数。当用户提到以下任何场景时都应触发:使用组合式函数、调用 Composables、判断设备类型、异步加载下拉选项、全屏 Loading、分页逻辑、监听路由变化、切换主题、设置页面标题、添加水印。即使用户没有明确说 Composables,只要意图是使用项目内置的组合式函数就应该使用此 Skill。 metadata: author: pany version: "2026.06.13"
内置组合式函数使用教程
项目在 src/common/composables 目录下提供了一组通用组合式函数,通过路径别名 @@/composables/ 导入。
本 Skill 定义的是项目内置的组合式函数,当这些函数不存在时,以用户需求为准,新增对应函数。
设备检测 useDevice
判断当前设备类型(移动端 / 桌面端),基于 appStore.device 的响应式计算属性。
import { useDevice } from "@@/composables/useDevice"
const { isMobile, isDesktop } = useDevice()
// 在模板或逻辑中使用
if (isMobile.value) {
// 移动端逻辑
}
异步下拉选择器 useFetchSelect
封装下拉选择器的异步数据加载逻辑,组件挂载时自动调用接口获取选项。
import { useFetchSelect } from "@@/composables/useFetchSelect"
import { getSelectDataApi } from "./apis/xxx"
const { loading, options, value } = useFetchSelect({
api: getSelectDataApi // 直接传函数引用,返回 ApiResponseData<SelectOption[]>
})
在模板中配合 Element Plus 使用:
<el-card v-loading="loading">
<el-select v-model="value" filterable>
<el-option v-for="item in options" v-bind="item" :key="item.value" placeholder="请选择" />
</el-select>
</el-card>
接口返回的数据格式:
interface SelectOption {
value: string | number
label: string
disabled?: boolean
}
全屏加载 useFullscreenLoading
包装一个函数,在其执行期间自动显示全屏 Loading,函数执行完毕后自动关闭。
import { useFullscreenLoading } from "@@/composables/useFullscreenLoading"
// 方式一:行内调用(推荐简单场景)
const res = await useFullscreenLoading(getSuccessApi)([1, 2, 3])
// 方式二:自定义 Loading 配置
try {
await useFullscreenLoading(getErrorApi, { text: "删除中...", background: "#F56C6C20" })()
} catch (error) {
ElMessage.error((error as Error).message)
}
// 方式三:先赋值再调用(适合多次复用)
const submitWithLoading = useFullscreenLoading(submitApi)
await submitWithLoading(formData)
分页 usePagination
封装分页状态与操作,适配 Element Plus 的 el-pagination 组件。
import { usePagination } from "@@/composables/usePagination"
function getTableData() {
// 请求表格数据,并更新 paginationData.total
}
const { paginationData, resetCurrentPage, watchPagination } = usePagination({
callback: getTableData,
pageSize: 20,
pageSizes: [10, 20, 50, 100]
})
// 初始化加载,并在 currentPage / pageSize 变化时重新请求
watchPagination()
function handleSearch() {
resetCurrentPage()
}
在模板中使用:
<el-pagination
v-model:current-page="paginationData.currentPage"
v-model:page-size="paginationData.pageSize"
:page-sizes="paginationData.pageSizes"
:total="paginationData.total"
:layout="paginationData.layout"
background
/>
callback 会在 watchPagination 监听到页码或每页条数变化时执行;resetCurrentPage 用于搜索场景,当前已在第 1 页时直接执行回调,否则重置到第 1 页并交给监听触发,避免重复请求。
默认分页参数:
| 参数 | 默认值 |
|---|---|
total |
0 |
currentPage |
1 |
pageSizes |
[10, 20, 50] |
pageSize |
10 |
layout |
"total, sizes, prev, pager, next, jumper" |
路由监听 useRouteListener
基于发布订阅模式监听路由变化,比直接 watch 路由性能更好,组件卸载时自动移除监听。
import { useRouteListener } from "@@/composables/useRouteListener"
const { listenerRouteChange, removeRouteListener } = useRouteListener()
// 监听路由变化
listenerRouteChange((route) => {
console.log("路由变化了:", route.path)
})
// 立即执行一次(获取当前路由信息)
listenerRouteChange((route) => {
activeMenu.value = route.path
}, true) // 第二个参数 immediate = true
主题切换 useTheme
管理主题切换,支持 View Transition 动画效果。
import { useTheme } from "@@/composables/useTheme"
const { themeList, activeThemeName, initTheme, setTheme } = useTheme()
// 初始化主题(应用启动时调用一次)
initTheme()
// 切换主题(需要传入鼠标事件以实现过渡动画)
function handleThemeChange(event: MouseEvent, themeName: ThemeName) {
setTheme(event, themeName)
}
可用主题:
| name | title |
|---|---|
"normal" |
默认 |
"dark" |
黑暗 |
"dark-blue" |
深蓝 |
动态标题 useTitle
动态设置浏览器标签页标题,格式为 项目名 | 页面名。
import { useTitle } from "@@/composables/useTitle"
const { setTitle } = useTitle()
// 设置标题为 "V3 Admin Vite | 用户管理"
setTitle("用户管理")
// 重置为项目默认标题
setTitle()
水印 useWatermark
为页面或指定容器添加水印,支持防御(防止用户通过控制台删除或隐藏水印),组件卸载时自动清除。
import { useWatermark } from "@@/composables/useWatermark"
// 默认挂载到 body
const { setWatermark, clearWatermark } = useWatermark()
// 设置水印
setWatermark("机密文件")
// 自定义配置
setWatermark("内部使用", {
defense: true, // 开启防御(默认 true)
color: "#c0c4cc", // 文本颜色
opacity: 0.5, // 透明度
size: 16, // 字体大小
angle: -20, // 倾斜角度
width: 300, // 单个水印宽度(越大密度越低)
height: 200 // 单个水印高度(越大密度越低)
})
// 清除水印
clearWatermark()
挂载到指定容器:
<script setup lang="ts">
import { useWatermark } from "@@/composables/useWatermark"
const localRef = useTemplateRef("localRef")
const { setWatermark, clearWatermark } = useWatermark(localRef)
onMounted(() => {
setWatermark("仅限内部")
})
</script>
<template>
<div ref="localRef">
<!-- 内容 -->
</div>
</template>
灰色模式与色弱模式 useGreyAndColorWeakness
初始化灰色模式和色弱模式,基于 settingsStore 的配置自动切换 HTML 根元素的 CSS 类名。
import { useGreyAndColorWeakness } from "@@/composables/useGreyAndColorWeakness"
const { initGreyAndColorWeakness } = useGreyAndColorWeakness()
// 应用启动时调用一次即可,后续会自动响应 Store 变化
initGreyAndColorWeakness()
布局模式 useLayoutMode
管理系统布局模式(左侧菜单 / 顶部菜单 / 左侧 + 顶部混合菜单)。
import { useLayoutMode } from "@@/composables/useLayoutMode"
import { LayoutModeEnum } from "@@/constants/app-key"
const { isLeft, isTop, isLeftTop, setLayoutMode } = useLayoutMode()
// 判断当前布局
if (isLeft.value) {
// 左侧菜单布局
}
// 切换布局
setLayoutMode(LayoutModeEnum.Top)
使用原则
- 优先使用这些内置组合式函数,不要重复造轮子
- 组合式函数内部已处理生命周期(如
onBeforeUnmount自动清理),无需手动管理 - 需要新增通用组合式函数时,在
src/common/composables目录下创建,命名以use开头 - 页面私有的组合式函数应放在对应页面目录的
composables子目录下,而非src/common/composables