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

Мы расскажем, как сохранить последний известный маршрут, а затем получить его, когда он нам понадобится. В этом примере мы будем работать во Vue и использовать vue-router для маршрутизации, а localStorage - для хранения информации о последнем посещенном маршруте.

Вот пример codeandbox того, с чем мы будем работать.

Сначала обрисуем структуру маршрута.

В нашем примере всего три маршрута:

  • /home
  • /hello
  • /goodbye

Каждому маршруту необходимо присвоить свойство name, поэтому давайте добавим его в наш файл router.js:

// router.js
import Vue from "vue"
import Router from "vue-router"
import Hello from "@/components/Hello"
import Goodbye from "@/components/Goodbye"
import {   HELLO_URL,   GOODBYE_URL } from "@/consts"
Vue.use(Router)
const router = new Router({
  mode: "history",
  routes: [
    { path: "/", name: "home" },
    { path: HELLO_URL, name: "hello", component: Hello },
    { path: GOODBYE_URL, name: "goodbye", component: Goodbye }
  ] })
export default router;

Затем давайте рассмотрим требования.

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

  • пользователь входит в основной маршрут (/home), уходит от него, а затем хочет вернуться к нему.
  • пользователь был неактивен в течение определенного периода времени, сеанс истекает, и мы хотим вернуть пользователя к последнему экрану, на котором он находился после перезапуска сеанса.

Эти четыре требования - то, что нам нужно выполнить, чтобы продолжить перенаправление.

Теперь перейдем к коду.

Требование 1. Сохраните последнее имя маршрута в localStorage.

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

Для этого мы хотим сохранить имя маршрута, когда пользователь вводит новый маршрут. Мы будем использовать навигационный щиток под названием afterEach, который срабатывает каждый раз, когда переход по маршруту завершается. Он предоставляет объект to, который является целевым объектом маршрута. В этой ловушке мы можем извлечь имя этого маршрута и сохранить его в localStorage, используя метод setItem.

// router.js
const router = new Router( ... )
router.afterEach(to => {
  localStorage.setItem(LS_ROUTE_KEY, to.name)
})
...
export default router

Требование 2: получить последнее имя маршрута из localStorage и перенаправить

Теперь, когда имя последнего маршрута сохранено, нам нужно иметь возможность получить его и инициировать перенаправление на него, когда это необходимо. Мы хотим проверить, следует ли выполнять перенаправление, прежде чем вводить новый маршрут, поэтому мы будем использовать другое средство навигации с именем beforeEach. У этого стража три аргумента:

  • to: целевой объект маршрута
  • from: текущий маршрут, откуда переходили
  • next: функция, которая должна быть вызвана в страже для разрешения перехвата

В этом страже мы читаем имя последнего посещенного маршрута с помощью метода localStorage.getItem(). Затем мы определяем, нужно ли перенаправлять пользователя. На этом этапе мы проверяем, является ли целевой маршрут (to) нашим основным маршрутом (/home) и действительно ли у нас есть последний маршрут в localStorage.

Если эти условия соблюдены, мы запускаем next метод, который содержит имя последнего посещенного маршрута. Это, в свою очередь, вызовет перенаправление на этот маршрут.

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

// router.js
const router = new Router( ... )
router.beforeEach((to, from, next) => {
  const lastRouteName = localStorage.getItem(LS_ROUTE_KEY)
  
  const shouldRedirect = Boolean(
     to.name === "home" &&
     lastRouteName
  )
  if (shouldRedirect) {
    next({ name: lastRouteName })
  } else {
    next()
  }
})
...
export default router

Это покрывает два из четырех требований! Перейдем к третьему требованию.

Требование 3: условие первого посещения

Теперь нам нужно проверить, посещает ли пользователь основной маршрут впервые (из другого источника) или перемещается по нему по другому маршруту в приложении. Мы можем сделать это, добавив флаг, для которого установлено значение true при создании маршрутизатора, и установить для него значение false после завершения первого перехода.

// router.js
const router = new Router( ... )
let isFirstTransition = true
router.beforeEach((to, from, next) => {
   const lastRouteName = localStorage.getItem(LS_ROUTE_KEY)         
   const shouldRedirect = Boolean(
     to.name === "home" &&
     && lastRouteName
     && isFirstTransition
   )
   
   if (shouldRedirect) {
     next({ name: lastRouteName })
   } else {
    next()
   }
   
   isFirstTransition = false
})
...
export default router

Хорошо, есть еще одно требование, которое нам необходимо выполнить: мы хотим перенаправить пользователя на последний известный маршрут, если пользователь неактивен дольше определенного периода времени.

Требование 4: условие времени активности

Опять же, мы будем использовать localStorage, чтобы сохранить информацию о маршруте, который пользователь последний раз посещал.

В beforeEach guard мы получим маршрут от localStorage и проверим, находится ли время, прошедшее с этого момента, в пределах нашего порогового значения (определяемого hasBeenActiveRecently). Затем в нашем shouldRedirect мы определим, должно ли происходить перенаправление маршрута.

Нам также необходимо сохранить эту информацию, что мы и сделаем в afterEach guard.

// router.js
const router = new Router( ... )
let isFirstTransition = true
router.beforeEach((to, from, next) => {
   const lastRouteName = localStorage.getItem(LS_ROUTE_KEY)   
   const lastActivityAt = 
     localStorage.getItem(LS_LAST_ACTIVITY_AT_KEY)
     
   const hasBeenActiveRecently = Boolean(
     lastActivityAt &&
     Date.now() - Number(lastActivityAt) < MAX_TIME_TO_RETURN
   )
    
   const shouldRedirect = Boolean(
     to.name === "home" &&
     && lastRouteName
     && isFirstTransition
     && hasBeenActiveRecently
   )
   if (shouldRedirect) {
     next({ name: lastRouteName })
   } else {
     next()
   }
   isFirstTransition = false
})
router.afterEach(to => {
   localStorage.setItem(LS_ROUTE_KEY, to.name)      
   localStorage.setItem(LS_LAST_ACTIVITY_AT_KEY, Date.now())
})
...
export default router

Мы выполнили требования!

Вот и все! Мы выполнили все четыре требования, а именно:

  • Мы сохраняем последний посещенный маршрут в localStorage
  • У нас есть способ получить последний посещенный маршрут из localStorage
  • Мы перенаправляем пользователя обратно на основной маршрут, если он входит в приложение при первом посещении.
  • Предоставляем пользователю перенаправление на последний известный маршрут в течение определенного периода времени.

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