Skip to content
This repository was archived by the owner on Apr 6, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions docs/content/3.api/2.components/4.nuxt-loading-indicator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# `<NuxtLoadingIndicator>`

::ReadMore{link="/guide/features/routing"}
::

Nuxt provides `<NuxtLoadingIndicator>` to display a progress bar on page navigation.

## Examples

### Basic usage

Add `<NuxtLoadingIndicator/>` in your `app.vue` or layouts.

```vue [app.vue]
<template>
<NuxtLayout>
<NuxtLoadingIndicator /> <!-- here -->
<NuxtPage />
<NuxtLayout>
</template>
```

:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/framework/tree/main/examples/routing/pages?terminal=dev&file=/app.vue" blank}

## Props

- **color**: The color of the loading bar.
- **height**: Height of the loading bar, in pixels (default `3`).
- **duration**: Duration of the loading bar, in milliseconds (default `2000`).
- **throttle**: Throttle the appearing and hiding, in milliseconds (default `200`).

::alert{type=info icon=πŸ”Ž}
This component is completely optional. To achieve full customization, you can implement your own one based on [this file](https://github.com/nuxt/framework/blob/main/packages/nuxt/src/app/components/nuxt-loading-bar.ts).
::
1 change: 1 addition & 0 deletions examples/routing/pages/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const route = useRoute()

<template>
<NuxtExampleLayout example="routing/pages">
<NuxtLoadingIndicator />
<NuxtPage />

<template #nav>
Expand Down
120 changes: 120 additions & 0 deletions packages/nuxt/src/app/components/nuxt-loading-indicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { computed, defineComponent, h, onBeforeUnmount, ref } from 'vue'
import { useNuxtApp } from '#app'

export default defineComponent({
name: 'NuxtLoadingIndicator',
props: {
throttle: {
type: Number,
default: 200
},
duration: {
type: Number,
default: 2000
},
height: {
type: Number,
default: 3
},
color: {
type: String,
default: 'repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)'
}
},
setup (props) {
const indicator = useLoadingIndicator({
duration: props.duration,
throttle: props.throttle
})

// Hook to app lifecycle
// TODO: Use unified loading API
const nuxtApp = useNuxtApp()
nuxtApp.hook('page:start', indicator.start)
nuxtApp.hook('page:finish', indicator.finish)
onBeforeUnmount(() => indicator.clear)

return () => h('div', {
class: 'nuxt-loading-indicator',
style: {
position: 'fixed',
top: 0,
right: 0,
left: 0,
pointerEvents: 'none',
width: `${indicator.progress.value}%`,
height: `${props.height}px`,
opacity: indicator.isLoading.value ? 1 : 0,
background: props.color,
backgroundSize: `${(100 / indicator.progress.value) * 100}% auto`,
transition: 'width 0.1s, height 0.4s, opacity 0.4s',
zIndex: 999999
}
})
}
})

function useLoadingIndicator (opts: {
duration: number,
throttle: number
}) {
const progress = ref(0)
const isLoading = ref(false)
const step = computed(() => 10000 / opts.duration)

let _timer: any = null
let _throttle: any = null

function start () {
clear()
progress.value = 0
isLoading.value = true
if (opts.throttle) {
if (process.client) {
_throttle = setTimeout(_startTimer, opts.throttle)
}
} else {
_startTimer()
}
}

function finish () {
progress.value = 100
_hide()
}

function clear () {
clearInterval(_timer)
clearTimeout(_throttle)
_timer = null
_throttle = null
}

function _increase (num: number) {
progress.value = Math.min(100, progress.value + num)
}

function _hide () {
clear()
if (process.client) {
setTimeout(() => {
isLoading.value = false
setTimeout(() => { progress.value = 0 }, 400)
}, 500)
}
}

function _startTimer () {
if (process.client) {
_timer = setInterval(() => { _increase(step.value) }, 100)
}
}

return {
progress,
isLoading,
start,
finish,
clear
}
}
6 changes: 6 additions & 0 deletions packages/nuxt/src/core/nuxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ async function initNuxt (nuxt: Nuxt) {
filePath: resolve(nuxt.options.appDir, 'components/nuxt-link')
})

// Add <NuxtLoadingIndicator>
addComponent({
name: 'NuxtLoadingIndicator',
filePath: resolve(nuxt.options.appDir, 'components/nuxt-loading-indicator')
})

for (const m of modulesToInstall) {
if (Array.isArray(m)) {
await installModule(m[0], m[1])
Expand Down