| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- import type { TopicList, UserListConfig, UserListsInit, UseTabList, UseTabListsInit } from '@/types'
- import ls from 'store2'
- export function useGlobal() {
- const ins = getCurrentInstance()!
- const ctx = ins.appContext.config.globalProperties
- const options = ins.type
- const route = useRoute()
- const router = useRouter()
- const globalStore = useGlobalStore()
- return {
- ctx,
- options,
- route,
- router,
- globalStore,
- }
- }
- /**
- * 竞态锁
- * @param fn 回调函数
- * @param autoUnlock 是否自动解锁
- * @description
- * ```
- * autoUnlock === true 不管 fn 返回什么, 都自动解锁
- * autoUnlock === false 不管 fn 返回什么, 都不自动解锁
- * autoUnlock === 'auto' 当 fn 返回 false 时, 不自动解锁, 返回其他值时, 自动解锁
- * ```
- * @example
- * ```
- * const Fn = useLockFn(async (key) => {
- * console.log(key)
- * }
- *
- * <div v-on:click="Fn(123)"></div>
- * ```
- */
- export function useLockFn(fn: AnyFn, autoUnlock: boolean | 'auto' = 'auto') {
- const lock = ref(false)
- return async (...args: any[]) => {
- if (lock.value) {
- return
- }
- lock.value = true
- try {
- const $return: any = await fn(...args)
- if (autoUnlock === true || (autoUnlock === 'auto' && $return !== false)) {
- lock.value = false
- }
- }
- catch (e) {
- lock.value = false
- throw e
- }
- }
- }
- export function useSaveScroll() {
- const ins = getCurrentInstance()
- const route = useRoute()
- let name: string | undefined = ''
- if (ins) {
- name = ins.type.name
- }
- onActivated(() => {
- if (name) {
- const body = document.querySelector(`.${name}`)
- if (body) {
- const scrollTop = ls.get(route.fullPath) || 0
- body.scrollTo(0, scrollTop)
- ls.remove(route.fullPath)
- }
- }
- })
- onBeforeRouteLeave((_to, from, next) => {
- const body = document.querySelector('.body')
- if (body) {
- ls.set(from.fullPath, body.scrollTop || 0)
- }
- next()
- })
- }
- /**
- * 单列表封装
- * @param init { api: 接口封装 }
- */
- export function useLists<T>(init: UserListsInit) {
- const globalStore = useGlobalStore()
- const body = $ref<HTMLElement>()!
- const res: UserListConfig<T> = reactive({
- ...init,
- timer: null,
- isLoaded: false,
- // 列表数据 ==>
- page: 1,
- dataList: [],
- // <==列表数据
- config: {
- // 下拉刷新 ==>
- isLoading: false,
- isRefresh: false,
- // <==下拉刷新
- // 滚动加载 ==>
- loadStatus: 'loadmore',
- isLock: false,
- loading: false,
- error: false,
- finished: false,
- // <==滚动加载
- },
- })
- /**
- * 请求列表接口
- */
- const getList = async () => {
- if (res.config.isLock) {
- return
- }
- res.config.isLock = true
- // 异步更新数据
- res.timer = setTimeout(() => {
- globalStore.$patch({ routerLoading: true })
- }, 500)
- // 第一页时不显示loading
- if (res.page > 1) {
- res.config.loading = true
- }
- const { data, code } = await $api[init.api.method]<ResDataLists<T>>(init.api.url, { ...init.api.config, page: res.page })
- // 500毫秒内已经加载完成数据, 则清除定时器, 不再显示路由loading
- if (res.timer) {
- clearTimeout(res.timer)
- }
- globalStore.$patch({ routerLoading: false })
- res.isLoaded = true
- if (code === 200) {
- // 如果是下拉刷新 或者是第1页, 则只保留当前数据
- if (res.config.isRefresh || res.page === 1) {
- res.dataList = [...data.list]
- res.config.isRefresh = false
- }
- else {
- res.dataList = res.dataList.concat(data.list)
- }
- await nextTick()
- // 加载状态结束
- res.config.loading = false
- // 数据全部加载完成
- if (!data.hasNext) {
- res.config.finished = true
- res.config.loadStatus = 'nomore'
- }
- else {
- res.config.loadStatus = 'loadmore'
- res.page += 1
- }
- res.config.isLock = false
- }
- else {
- res.config.error = true
- }
- }
- /**
- * 刷新接口
- */
- const onRefresh = async () => {
- res.config.isRefresh = true
- res.page = 1
- await getList()
- res.config.isLoading = false
- }
- /**
- * 触底回调
- */
- const reachBottom = () => {
- if (res.config.loadStatus === 'nomore' || res.config.loadStatus === 'loading') {
- return
- }
- res.config.loadStatus = 'loading'
- getList()
- }
- const lazyLoading = () => {
- // 滚动到底部,再加载的处理事件
- const scrollTop = body.scrollTop
- const clientHeight = body.clientHeight
- const scrollHeight = body.scrollHeight
- if (scrollTop + clientHeight >= scrollHeight - 300) {
- reachBottom()
- }
- }
- return {
- ...toRefs(res),
- body,
- getList,
- onRefresh,
- reachBottom,
- lazyLoading,
- }
- }
- /**
- * Tab接口列表
- * @param init { api: 接口封装 }
- */
- export function useTabLists<T>(init: UseTabListsInit) {
- const { options, globalStore } = useGlobal()
- const body = $ref<HTMLElement>()!
- const res: UseTabList<T> = reactive({
- ...init,
- timer: null,
- // 列表数据 ==>
- list: Array.from({ length: 5 }, () => '').map(() => ({
- page: 1,
- items: [],
- refreshing: false,
- loading: false,
- error: false,
- finished: false,
- })),
- // <==列表数据
- })
- const activeIndex = ref(0)
- const getList = async (index: number) => {
- const list: TopicList<T> = JSON.parse(JSON.stringify(res.list[index]))
- if (list.page === 1) {
- const body = document.querySelector(`.${options.name}`)
- if (body)
- body.scrollTo(0, 0)
- }
- // 500毫秒数据还没请求完成, 显示路由loading
- res.timer = setTimeout(() => {
- globalStore.$patch({ routerLoading: true })
- }, 500)
- // 第一页直接用路由loading
- if (list.page === 1) {
- list.loading = false
- }
- // 异步更新数据
- const { method, url, config } = res.api[index]
- const { code, data } = await $api[method as Methods]<ResDataLists<T>>(url, { ...config, page: list.page })
- // 500毫秒内已经加载完成数据, 则清除定时器, 不再显示路由loading
- if (res.timer) {
- clearTimeout(res.timer)
- }
- globalStore.$patch({ routerLoading: false })
- if (code === 200) {
- // 如果是下拉刷新, 则只保留当前数据
- if (list.refreshing) {
- list.items = [...data.list]
- list.refreshing = false
- }
- else {
- list.items = list.items.concat(data.list)
- }
- await nextTick()
- // 加载状态结束
- list.loading = false
- // 数据全部加载完成
- if (!data.hasNext) {
- list.finished = true
- }
- else {
- list.page += 1
- }
- }
- else {
- list.error = true
- }
- res.list.splice(index, 1, list)
- }
- const onRefresh = async (index: number) => {
- res.list[index].refreshing = true
- res.list[index].page = 1
- await getList(index)
- res.list[index].refreshing = false
- showMsg('刷新成功')
- }
- return {
- res,
- body,
- getList,
- onRefresh,
- activeIndex,
- }
- }
|