🧩 useDetailLoader
组合函数封装(支持自动加载 + 页面判断 + 防重复)
✅ 功能特点
- ✅ 自动监听
query.id
(或指定字段) - ✅ 只在指定页面名称时才触发(避免跳转到其他页面时误触发)
- ✅ 避免同一 id 重复加载
- ✅ 支持初始加载和浏览器返回场景
- ✅ 支持动态更新 loading 状态
📦 useDetailLoader.ts
import { watch, ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
interface UseDetailLoaderOptions {
routeName: string
queryKey?: string
immediate?: boolean
fetch: (id: string) => Promise<any>
onSuccess?: (data: any) => void
onError?: (err: any) => void
}
export function useDetailLoader(options: UseDetailLoaderOptions) {
const route = useRoute()
const idKey = options.queryKey || 'id'
const currentId = ref<string | null>(null)
const loading = ref(false)
const load = async (id: string) => {
if (!id || id === currentId.value) return
currentId.value = id
loading.value = true
try {
const data = await options.fetch(id)
options.onSuccess?.(data)
} catch (err) {
options.onError?.(err)
console.error('详情加载失败', err)
} finally {
loading.value = false
}
}
onMounted(() => {
const id = route.query[idKey]
if (options.immediate && typeof id === 'string' && route.name === options.routeName) {
load(id)
}
})
watch(() => route.query[idKey], (newId) => {
if (route.name !== options.routeName) return
if (typeof newId === 'string') {
load(newId)
}
})
return {
loading,
currentId,
reload: () => {
const id = route.query[idKey]
if (typeof id === 'string') {
load(id)
}
}
}
}
🧪 示例用法:详情页中加载业绩数据
const detailInfo = ref({})
const detailLoading = ref(false)
const { loading, reload } = useDetailLoader({
routeName: 'PerformanceDetail',
fetch: async (id) => {
const res = await getManagerPerformanceInfo({ userId: id })
return res.data
},
onSuccess: (data) => {
detailInfo.value = data || {}
currencySymbol.value = data.exchange || '¥'
},
onError: () => {
ElMessage.error('获取详情失败')
},
immediate: true
})
🧠 搭配列表请求也可以:
const performanceList = ref([])
const getList = async (id: string) => {
const res = await getPerformanceOrderList({ userId: id, ...queryParams.value })
performanceList.value = res.rows || []
}
useDetailLoader({
routeName: 'PerformanceDetail',
fetch: async (id) => {
await getList(id)
return null
},
immediate: true
})
🧩 支持的配置项一览
参数 | 类型 | 说明 |
---|
routeName | string | 当前页面的路由名称 |
queryKey | string | 监听哪个 query 字段(默认 id ) |
immediate | boolean | 是否在首次进入时立即加载 |
fetch | (id) => Promise<any> | 数据获取函数 |
onSuccess | (data) => void | 请求成功时回调 |
onError | (err) => void | 请求失败时回调 |
📚 总结
useDetailLoader
是一个用于详情页按需监听参数加载的通用 Hook,具备以下优势:
- ✅ 自动监听,避免重复加载
- ✅ 不受非当前页跳转影响
- ✅ 可读性高,方便团队复用
- ✅ 易于拓展支持 params、动态参数等