Индикаторы выполнения

Поскольку запросы инерции выполняются через XHR, индикатор загрузки браузера по умолчанию при переходе с одной страницы на другую отсутствует. Чтобы решить эту проблему, Inertia предоставляет необязательную библиотеку progress, которая показывает полосу загрузки всякий раз, когда Вы совершаете посещение Inertia. Также можно установить свои собственные индикаторы загрузки страниц. На этой странице объясняются оба подхода.

По умолчанию

Библиотека прогресса Inertia по умолчанию (@inertiajs/progress) представляет собой легкую оболочку вокруг NProgress. Эта библиотека показывает, обновляет и скрывает полосу загрузки NProgress, слушая посещение страницы Inertia события.

Чтобы использовать его, начните с его установки:

npm install @inertiajs/progress
yarn add @inertiajs/progress

После установки инициализируйте его в своем приложении.

import { InertiaProgress } from '@inertiajs/progress'

InertiaProgress.init()

Он также предоставляет ряд параметров настройки, которые Вы передаете методу init().

InertiaProgress.init({
  // Задержка в миллисекундах, после которой
  // во время навигации появится индикатор выполнения.
  delay: 250,

  // Цвет индикатора выполнения.
  color: '#29d',

  // Следует ли включать стили NProgress по умолчанию.
  includeCSS: true,

  // Будет ли отображаться счетчик NProgress.
  showSpinner: false,
})

Пользовательский

Также можно настроить свои собственные индикаторы загрузки страниц, используя события Inertia. Вот как это сделать на примере библиотеки NProgress.

Сначала установите библиотеку NProgress.

npm install nprogress
yarn add nprogress

Вам нужно будет добавить NProgress стили в свой проект. Вы можете сделать это, используя версию CDN.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" />

Затем импортируйте в свое приложение как NProgress, так и Inertia.

import NProgress from 'nprogress'
import { Inertia } from '@inertiajs/inertia'

Затем давайте добавим слушателя событий start. Мы будем использовать этот слушатель, чтобы показывать индикатор выполнения, когда начинается новое посещение Inertia.

Inertia.on('start', () => NProgress.start())

Затем давайте добавим прослушиватель событий finish, чтобы скрыть индикатор выполнения по завершении посещения страницы.

Inertia.on('finish', () => NProgress.done())

Вот и все, теперь у Dас есть рабочий индикатор загрузки страницы! Когда Dы переходите с одной страницы на другую, индикатор выполнения будет добавляться и удаляться со страницы.

Обработка отмененных посещений

Хотя эта реализация отлично подходит для посещений, которые завершаются должным образом, было бы неплохо обрабатывать отмененные посещения немного лучше. Во-первых, для прерванных посещений (тех, которые были отменены в результате нового посещения) индикатор выполнения нужно просто вернуть в исходное положение. Во-вторых, для вручную отмененных посещений индикатор выполнения должен быть немедленно удален со страницы.

Мы можем сделать это, проверив объект event.detail.visit, предоставленный событию finish.

Inertia.on('finish', (event) => {
  if (event.detail.visit.completed) {
    NProgress.done()
  } else if (event.detail.visit.interrupted) {
    NProgress.set(0)
  } else if (event.detail.visit.cancelled) {
    NProgress.done()
    NProgress.remove()
  }
})

Намного лучше!

Ход загрузки файла

Давайте сделаем еще один шаг вперед. Когда файлы загружаются, было бы неплохо обновить индикатор загрузки, чтобы отражать прогресс загрузки. Это можно сделать с помощью события progress.

Inertia.on('progress', (event) => {
  if (event.detail.progress.percentage) {
    NProgress.set((event.detail.progress.percentage / 100) * 0.9)
  }
})

Теперь вместо того, чтобы индикатор выполнения «просачивался» во время загрузки файлов, он фактически обновляет свое положение в зависимости от хода выполнения запроса. Мы ограничиваем прогресс здесь до 90%, так как нам еще нужно дождаться ответа от сервера.

Задержка индикатора загрузки

Последнее, что мы собираемся реализовать, - это задержка индикатора загрузки. Часто предпочтительнее отложить отображение индикатора загрузки до тех пор, пока запрос не займет более 250ms-500ms. Это предотвращает постоянное появление индикатора загрузки при быстром посещении страницы, что может визуально отвлекать.

Чтобы реализовать поведение задержки, мы будем использовать функции setTimeout и clearTimeout. Начнем с определения переменной для отслеживания тайм-аута.

let timeout = null

Затем давайте обновим прослушиватель событий start, чтобы начать новый тайм-аут, который покажет индикатор выполнения после 250ms.

Inertia.on('start', () => {
  timeout = setTimeout(() => NProgress.start(), 250)
})

Затем мы обновим прослушиватель событий finish, чтобы очистить все существующие тайм-ауты в случае, если посещение страницы завершается раньше, чем истечет время ожидания.

Inertia.on('finish', (event) => {
  clearTimeout(timeout)
  // ...
})

Нам также необходимо проверить в прослушивателе событий finish, действительно ли запущен индикатор выполнения, иначе мы случайно заставим его отобразить его до истечения тайм-аута.

Inertia.on('finish', (event) => {
  clearTimeout(timeout)
  if (!NProgress.isStarted()) {
    return
  }
  // ...
})

И, наконец, нам нужно сделать такую же проверку в слушателе событий progress.

Inertia.on('progress', event => {
  if (!NProgress.isStarted()) {
    return
  }
  // ...
}

Вот и все, теперь у вас есть красивый индикатор загрузки пользовательской страницы!

Полный пример

Для Вашей быстрой справки, вот полный исходный код финальной версии.

import NProgress from 'nprogress'
import { Inertia } from '@inertiajs/inertia'

let timeout = null

Inertia.on('start', () => {
  timeout = setTimeout(() => NProgress.start(), 250)
})

Inertia.on('progress', (event) => {
  if (NProgress.isStarted() && event.detail.progress.percentage) {
    NProgress.set((event.detail.progress.percentage / 100) * 0.9)
  }
})

Inertia.on('finish', (event) => {
  clearTimeout(timeout)
  if (!NProgress.isStarted()) {
    return
  } else if (event.detail.visit.completed) {
    NProgress.done()
  } else if (event.detail.visit.interrupted) {
    NProgress.set(0)
  } else if (event.detail.visit.cancelled) {
    NProgress.done()
    NProgress.remove()
  }
})