Этот ответ должен работать с одностраничным приложением push-state, многостраничным приложением или их комбинацией. (Исправлено, чтобы исправить ошибку History.length
, указанную в комментарии Мескалито.)
Как это работает
Мы можем легко прослушивать новые записи в стеке истории.Мы знаем, что для каждой новой записи спецификация требует от браузера:
- «Удалить все записи в истории сеанса контекста просмотра после текущей записи»
- «Добавить новую запись в конце»
Следовательно, в момент входа:
новая позиция входа = последняя отображенная позиция + 1
Тогда решение будет таким:
- Пометить каждую запись истории с ее собственной позицией в стеке
- Отслеживать в хранилище сессий последнюю показанную позицию
- Узнайте направление движения, сравнив два
Пример кода
function reorient() // After travelling in the history stack
{
const positionLastShown = Number( // If none, then zero
sessionStorage.getItem( 'positionLastShown' ));
let position = history.state; // Absolute position in stack
if( position === null ) // Meaning a new entry on the stack
{
position = positionLastShown + 1; // Top of stack
// (1) Stamp the entry with its own position in the stack
history.replaceState( position, /*no title*/'' );
}
// (2) Keep track of the last position shown
sessionStorage.setItem( 'positionLastShown', String(position) );
// (3) Discover the direction of travel by comparing the two
const direction = Math.sign( position - positionLastShown );
console.log( 'Travel direction is ' + direction );
// One of backward (-1), reload (0) or forward (1)
}
addEventListener( 'pageshow', reorient );
addEventListener( 'popstate', reorient ); // Travel in same page
См. Также живую копию кода.
Ограничение
Это решение игнорирует записи истории внешних страниц, чуждых приложению, как если бы пользователь никогда не посещал их.Он рассчитывает направление движения только относительно последней показанной страницы приложения, независимо от того, какая внешняя страница была посещена между ними.Если вы ожидаете, что пользователь поместит чужие записи в стек (см. Комментарий Atomosk), вам может потребоваться обходной путь.