feat(nuxt): allow forcing start/set in loading indicator (#30989)

This commit is contained in:
xjccc 2025-02-15 03:01:26 +08:00 committed by Daniel Roe
parent 72159e0808
commit a85ca58382
No known key found for this signature in database
GPG Key ID: CBC814C393D93268
3 changed files with 40 additions and 9 deletions

View File

@ -40,7 +40,11 @@ It hooks into [`page:loading:start`](/docs/api/advanced/hooks#app-hooks-runtime)
### `start()` ### `start()`
Set `isLoading` to true and start to increase the `progress` value. Set `isLoading` to true and start to increase the `progress` value. `start` accepts a `{ force: true }` option to skip the interval and show the loading state immediately.
### `set()`
Set the `progress` value to a specific value. `set` accepts a `{ force: true }` option to skip the interval and show the loading state immediately.
### `finish()` ### `finish()`
@ -62,3 +66,12 @@ Used by `finish()`. Clear all timers and intervals used by the composable.
}) })
</script> </script>
``` ```
```vue
<script setup lang="ts">
const { start, set } = useLoadingIndicator()
// same as set(0, { force: true })
// set the progress to 0, and show loading immediately
start({ force: true })
</script>
```

View File

@ -24,8 +24,8 @@ export type LoadingIndicator = {
progress: Ref<number> progress: Ref<number>
isLoading: Ref<boolean> isLoading: Ref<boolean>
error: Ref<boolean> error: Ref<boolean>
start: () => void start: (opts?: { force?: boolean }) => void
set: (value: number) => void set: (value: number, opts?: { force?: boolean }) => void
finish: (opts?: { force?: boolean, error?: boolean }) => void finish: (opts?: { force?: boolean, error?: boolean }) => void
clear: () => void clear: () => void
} }
@ -49,23 +49,24 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
let hideTimeout: number | NodeJS.Timeout let hideTimeout: number | NodeJS.Timeout
let resetTimeout: number | NodeJS.Timeout let resetTimeout: number | NodeJS.Timeout
const start = () => { const start = (opts: { force?: boolean } = {}) => {
error.value = false error.value = false
set(0) set(0, opts)
} }
function set (at = 0) { function set (at = 0, opts: { force?: boolean } = {}) {
if (nuxtApp.isHydrating) { if (nuxtApp.isHydrating) {
return return
} }
if (at >= 100) { return finish() } if (at >= 100) { return finish({ force: opts.force }) }
clear() clear()
progress.value = at < 0 ? 0 : at progress.value = at < 0 ? 0 : at
if (throttle && import.meta.client) { const throttleTime = opts.force ? 0 : throttle
if (throttleTime && import.meta.client) {
throttleTimeout = setTimeout(() => { throttleTimeout = setTimeout(() => {
isLoading.value = true isLoading.value = true
_startProgress() _startProgress()
}, throttle) }, throttleTime)
} else { } else {
isLoading.value = true isLoading.value = true
_startProgress() _startProgress()

View File

@ -530,6 +530,23 @@ describe('loading state', () => {
}) })
}) })
describe('loading state', () => {
it('expect state from set opts: { force: true }', async () => {
vi.stubGlobal('setTimeout', vi.fn((cb: () => void) => cb()))
const nuxtApp = useNuxtApp()
const { isLoading, start, finish, set } = useLoadingIndicator()
await nuxtApp.callHook('page:loading:start')
start({ force: true })
expect(isLoading.value).toBeTruthy()
finish()
expect(isLoading.value).toBeFalsy()
set(0, { force: true })
expect(isLoading.value).toBeTruthy()
set(100, { force: true })
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()