mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-13 09:33:54 +00:00
feat(nuxt): custom loading reset/hide delay + force finish()
(#25932)
This commit is contained in:
parent
7095048f3b
commit
83314f1c95
@ -7,6 +7,10 @@ export type LoadingIndicatorOpts = {
|
|||||||
duration: number
|
duration: number
|
||||||
/** @default 200 */
|
/** @default 200 */
|
||||||
throttle: number
|
throttle: number
|
||||||
|
/** @default 500 */
|
||||||
|
hideDelay: number
|
||||||
|
/** @default 400 */
|
||||||
|
resetDelay: number
|
||||||
/**
|
/**
|
||||||
* You can provide a custom function to customize the progress estimation,
|
* You can provide a custom function to customize the progress estimation,
|
||||||
* which is a function that receives the duration of the loading bar (above)
|
* which is a function that receives the duration of the loading bar (above)
|
||||||
@ -15,22 +19,13 @@ export type LoadingIndicatorOpts = {
|
|||||||
estimatedProgress?: (duration: number, elapsed: number) => number
|
estimatedProgress?: (duration: number, elapsed: number) => number
|
||||||
}
|
}
|
||||||
|
|
||||||
function _hide (isLoading: Ref<boolean>, progress: Ref<number>) {
|
|
||||||
if (import.meta.client) {
|
|
||||||
setTimeout(() => {
|
|
||||||
isLoading.value = false
|
|
||||||
setTimeout(() => { progress.value = 0 }, 400)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LoadingIndicator = {
|
export type LoadingIndicator = {
|
||||||
_cleanup: () => void
|
_cleanup: () => void
|
||||||
progress: Ref<number>
|
progress: Ref<number>
|
||||||
isLoading: Ref<boolean>
|
isLoading: Ref<boolean>
|
||||||
start: () => void
|
start: () => void
|
||||||
set: (value: number) => void
|
set: (value: number) => void
|
||||||
finish: () => void
|
finish: (opts: { force?: boolean }) => void
|
||||||
clear: () => void
|
clear: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +35,7 @@ function defaultEstimatedProgress (duration: number, elapsed: number): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
||||||
const { duration = 2000, throttle = 200 } = opts
|
const { duration = 2000, throttle = 200, hideDelay = 500, resetDelay = 400 } = opts
|
||||||
const getProgress = opts.estimatedProgress || defaultEstimatedProgress
|
const getProgress = opts.estimatedProgress || defaultEstimatedProgress
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const progress = ref(0)
|
const progress = ref(0)
|
||||||
@ -48,7 +43,9 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
|||||||
let done = false
|
let done = false
|
||||||
let rafId: number
|
let rafId: number
|
||||||
|
|
||||||
let _throttle: any = null
|
let throttleTimeout: number | NodeJS.Timeout
|
||||||
|
let hideTimeout: number | NodeJS.Timeout
|
||||||
|
let resetTimeout: number | NodeJS.Timeout
|
||||||
|
|
||||||
const start = () => set(0)
|
const start = () => set(0)
|
||||||
|
|
||||||
@ -60,7 +57,7 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
|||||||
clear()
|
clear()
|
||||||
progress.value = at < 0 ? 0 : at
|
progress.value = at < 0 ? 0 : at
|
||||||
if (throttle && import.meta.client) {
|
if (throttle && import.meta.client) {
|
||||||
_throttle = setTimeout(() => {
|
throttleTimeout = setTimeout(() => {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
_startProgress()
|
_startProgress()
|
||||||
}, throttle)
|
}, throttle)
|
||||||
@ -70,19 +67,40 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function finish () {
|
function _hide () {
|
||||||
|
if (import.meta.client) {
|
||||||
|
hideTimeout = setTimeout(() => {
|
||||||
|
isLoading.value = false
|
||||||
|
resetTimeout = setTimeout(() => { progress.value = 0 }, resetDelay)
|
||||||
|
}, hideDelay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish (opts: { force?: boolean } = {}) {
|
||||||
progress.value = 100
|
progress.value = 100
|
||||||
done = true
|
done = true
|
||||||
clear()
|
clear()
|
||||||
_hide(isLoading, progress)
|
_clearTimeouts()
|
||||||
|
if (opts.force) {
|
||||||
|
progress.value = 0
|
||||||
|
isLoading.value = false
|
||||||
|
} else {
|
||||||
|
_hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _clearTimeouts () {
|
||||||
|
if (import.meta.client) {
|
||||||
|
clearTimeout(hideTimeout)
|
||||||
|
clearTimeout(resetTimeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear () {
|
function clear () {
|
||||||
clearTimeout(_throttle)
|
|
||||||
if (import.meta.client) {
|
if (import.meta.client) {
|
||||||
|
clearTimeout(throttleTimeout)
|
||||||
cancelAnimationFrame(rafId)
|
cancelAnimationFrame(rafId)
|
||||||
}
|
}
|
||||||
_throttle = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _startProgress () {
|
function _startProgress () {
|
||||||
@ -113,7 +131,7 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
|||||||
const unsubLoadingFinishHook = nuxtApp.hook('page:loading:end', () => {
|
const unsubLoadingFinishHook = nuxtApp.hook('page:loading:end', () => {
|
||||||
finish()
|
finish()
|
||||||
})
|
})
|
||||||
const unsubError = nuxtApp.hook('vue:error', finish)
|
const unsubError = nuxtApp.hook('vue:error', () => finish())
|
||||||
|
|
||||||
_cleanup = () => {
|
_cleanup = () => {
|
||||||
unsubError()
|
unsubError()
|
||||||
|
@ -487,6 +487,21 @@ describe('loading state', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('loading state', () => {
|
||||||
|
it('expect loading state to be changed by force starting/stoping', async () => {
|
||||||
|
vi.stubGlobal('setTimeout', vi.fn((cb: Function) => cb()))
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const { isLoading, start, finish } = useLoadingIndicator()
|
||||||
|
expect(isLoading.value).toBeFalsy()
|
||||||
|
await nuxtApp.callHook('page:loading:start')
|
||||||
|
expect(isLoading.value).toBeTruthy()
|
||||||
|
start()
|
||||||
|
expect(isLoading.value).toBeTruthy()
|
||||||
|
finish()
|
||||||
|
expect(isLoading.value).toBeFalsy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', () => {
|
describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', () => {
|
||||||
it('getAppManifest', async () => {
|
it('getAppManifest', async () => {
|
||||||
const manifest = await getAppManifest()
|
const manifest = await getAppManifest()
|
||||||
|
Loading…
Reference in New Issue
Block a user