Здравствуйте. Я работаю над проектом для практики. Это одностраничное приложение, которое я намерен реализовать исключительно с использованием JS, CSS, HTML и Node.js, без применения фреймворков и библиотек. У меня возникла проблема, связанная с событием popstate, в частности с попыткой сохранить состояние прокрутки страницы в объекте state для каждой страницы. Я пробовал использовать pushState и replaceState, но столкнулся с тем, что при возвращении назад более свежие записи удаляются. Я исследовал различные способы перейти по истории браузера назад, не применяя эти команды, и не нашел подходящих инструментов в стандартных возможностях браузера. Это делает использование React и подобных решений неприемлемым для этого эксперимента.
Итак, суть вопроса: <br/> У меня есть одностраничное браузерное приложение. При загрузке нового контента создается снимок текущего состояния, включая прокрутку. При шаге назад я изменяю состояние прокрутки с помощью replaceState. Все это реализовано в моем скрипте main_data.js: <br/> <pre><code class="javascript">"use strict"
window.history.scrollRestoration = "manual";
let main = document.getElementsByTagName("main")[0],
subMenu = document.querySelector("#subMenu");
window.addEventListener("popstate", async(e) => {
history.replaceState({ name: cp(), scroll: { x: window.scrollX, y: window.scrollY }, path:window.location.pathname }, "", window.location.pathname);
if (e.state) {
switch(e.state.name){
case 'main':
await res();
break;
default:
await contentF(e.state.name);
}
}
const { x, y } = e.state.scroll;
window.scrollTo(x, y);
});
document.addEventListener("pointerdown", async (e) => {
if(e.target.hasAttribute("da
Из вашего вопроса видно, что вы используете History API для управления состоянием прокрутки и загрузки контента в вашем одностраничном приложении. Давайте рассмотрим, как эффективно использовать `pushState` и `replaceState`, чтобы сохранить состояние прокрутки и избежать удаления более свежих записей в истории.
### Работа с History API
1. **Использование `pushState`**: Каждое состояние, которое вы хотите сохранить в истории, должно быть добавлено с помощью `pushState`. Это создаст новый элемент истории. Например:
```javascript
function navigateTo(pageName) {
const state = {
name: pageName,
scroll: { x: window.scrollX, y: window.scrollY },
path: window.location.pathname
};
window.history.pushState(state, "", pageName);
loadContent(pageName);
}
```
2. **Использование `replaceState`**: Если вы хотите обновить текущее состояние без добавления нового элемента в историю, вы используете `replaceState`. Это полезно для обновления состояния при использовании кнопки "Назад". Например, чтобы сохранить состояние прокрутки при переключении между страницами:
```javascript
function updateScrollState() {
const state = {
name: cp(),
scroll: { x: window.scrollX, y: window.scrollY },
path: window.location.pathname
};
window.history.replaceState(state, "", window.location.pathname);
}
```
3. **Обработка событий popstate**: Когда пользователь возвращается на предыдущую страницу, событие `popstate` будет вызвано. Ваша задача — обработать это событие, корректно восстанавливая состояние:
```javascript
window.addEventListener("popstate", async (e) => {
if (e.state) {
// Загрузка контента в зависимости от состояния
switch (e.state.name) {
case 'main':
await res();
break;
default:
await contentF(e.state.name);
}
// Восстановление прокрутки
const { x, y } = e.state.scroll;
window.scrollTo(x, y);
}
});
```
### Загрузка нового контента
Когда вы загружаете новый контент на страницу, вам нужно обновить состояние истории. Обычно это будет происходить при навигации, например, при клике на ссылки:
```javascript
document.addEventListener("pointerdown", async (e) => {
if (e.target.hasAttribute("data-navigate")) {
e.preventDefault();
const pageName = e.target.getAttribute("data-page"); // Получаем имя страницы
updateScrollState(); // Обновление текущего состояния прокрутки
navigateTo(pageName); // Переход к новой странице
}
});
```
### Важно
- Убедитесь, что у вас есть уникальные состояния для каждой страницы, которые вы хотите загрузить. Это позволит избежать путаницы и проблем с обновлением состояния.
- Используйте `replaceState` только тогда, когда вы не хотите добавлять новое состояние в историю (например, вы обновляете текущее состояние прокрутки).
- При манипуляциях с состоянием, следите за тем, чтобы каждая запись в истории имела полный набор необходимой информации для восстановления состояния (например, нужный контент и позицию прокрутки).
Используя вышеуказанные рекомендации, вы сможете гибко управлять состоянием прокрутки и контента вашего одностраничного приложения, избегая путаницы с историей навигации.
Всё оказалось проще чем я думал. Просто надо было прикрепить replaceState к событию прокрутки и немного подтроттлить его: <br/> <pre><code class="javascript">let scrollE = () => {
scrollP = window.scrollY;;
history.replaceState({name: cp(), scroll: scrollP, path: window.location.pathname},"",window.location.pathname);
}
let throttle = (callee, timeout) => {
let timer = null;
return function perform(...arg){
if(timer) return;
timer = setTimeout(() => {
callee(...arg);
timer = null;
}, timeout);
}
}
let scrollET = throttle(scrollE, 100);
window.addEventListener("scroll", scrollET);
window.addEventListener("popstate", async(e) => {
if (e.state) {
switch(e.state.name){
case 'relax':
relaxWork("y");
break;
case 'main':
await res("y");
break;
default:
await contentF(e.state.name, "y");
}
window.scrollTo(0, e.state.scroll);
}
});</code></pre>