Js событие назад в браузере

Обновлено: 02.07.2024

Почему же кнопки браузера не запускают свои собственные события !?

(Примечание: в соответствии с отзывами Шарки я включил код для обнаружения возврата)

Итак, я часто сталкивался с этими вопросами в SO, и недавно столкнулся с проблемой управления функциональностью кнопки возврата самостоятельно. После нескольких дней поиска лучшего решения для моего приложения (одностраничный с хэш-навигацией) я нашел простую, кросс-браузерную, безбиблиотечную систему для обнаружения кнопки «назад».

Большинство людей рекомендуют использовать:

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

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

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

Я также использую кнопку возврата на странице, которая перемещает пользователя между страницами с помощью lasthash массива. Это выглядит так:

Так что это переместит пользователя обратно к последнему хешу и удалит этот последний хеш из массива (у меня сейчас нет кнопки вперед).

Так. Как определить, использовал ли пользователь мою кнопку возврата на странице или кнопку браузера?

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

Итак, после еще нескольких копаний я увидел рекомендации по установке переменной-флага. Проблема с этим в моем случае заключается в том, что я попытался бы установить его, но, поскольку все является асинхронным, он не всегда будет установлен вовремя для оператора if в изменении хеша. .onMouseDown не всегда вызывался в клике, и добавление его в onclick никогда не вызывало бы его достаточно быстро.

Это когда я начал смотреть на разницу между document , и window . Мое окончательное решение состояло в том, чтобы установить флаг, используя document.onmouseover , и отключить его, используя document.onmouseleave .

Что происходит, когда мышь пользователя находится внутри области документа (читай: отображаемая страница, но исключая фрейм браузера), мой логический параметр установлен на true . Как только мышь покидает область документа, логическое значение переходит на false .

Таким образом, я могу изменить свой window.onhashchange на:

Итак, вкратце, и для людей, которые не обязательно используют кнопку возврата на странице или массив для хранения истории:

Чтобы убедиться, что пользователь не использует backspace для запуска события back, вы также можете добавить следующее (спасибо @thetoolman по этому вопросу ):

Как перехватить событие возврата на страницу, чтобы можно было ее обновить?

390 1 1 золотой знак 3 3 серебряных знака 12 12 бронзовых знаков Вам нужно не перехватывать "назад", а сохранять изменения на первой странице (на бэкенд, или на клиенте, в local storage или куки), и восстанавливать его при навигации назад. @Qwertiy незапощенные ответы на SO сохраняет браузер, а на все остальное они забили из соображений простоты :) Изменения на первой странице и так сохраняются (на сервере), но чтобы их восстановить - требуется перехватить событие возврата на страницу.

Раз пользователь может изменить вид страницы, значит, работает javascript. В нем надо при обработке пользовательских действий подменить последний элемент в истории браузера, чтобы возврат происходил уже на указанную вами страницу (или тот же адрес, но с параметрами).


28.2k 4 4 золотых знака 22 22 серебряных знака 49 49 бронзовых знаков В таком случае (обработка любого перехода по ссылке) лучше все-таки использовать replaceState , а не pushState . Иначе пользователю придется нажимать кнопку "назад" два раза, чтобы покинуть эту страницу. В качестве примера приведен довольно глючный сайт, особенно под отладчиком он не хотел нормально работать, плюс куча минифицированного кода, в котором не разберешься. Но что интересно - нужный функционал там был. Правда, он был не в javascript, а в заголовке Cache-Control: no-cache, no-store, must-revalidate. У меня же было просто Cache-Control: no-cache.

В комментариях верно написали, что ответ кроется не в перехвате события "назад" у браузера, а сохранении состояния страницы

Например, пользователь может изменить тему страницы. Что бы при возвращении на эту страницу, была выбрана нужная тема, сохраним ее в localStorage

Дальше, при нужных вам событиях, вы просто сохраняете в localStorage нужные вам данные, а при загрузке страницы ( onload событие, например) выгружаете нужные данные и используете их


12k 1 1 золотой знак 19 19 серебряных знаков 37 37 бронзовых знаков @PavelMayorov, не так сложно добавить проверку на время или другие условия для удаления состояния.

Перехватить событие возврата на страницу не получилось, задача решена другим способом.

При обновлении страницы по F5 также получаем с сервера самое последнее состояние страницы.

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

Вот список самых часто используемых DOM-событий, пока просто для ознакомления:

События мыши:

  • click – происходит, когда кликнули на элемент левой кнопкой мыши (на устройствах с сенсорными экранами оно происходит при касании).
  • contextmenu – происходит, когда кликнули на элемент правой кнопкой мыши.
  • mouseover / mouseout – когда мышь наводится на / покидает элемент.
  • mousedown / mouseup – когда нажали / отжали кнопку мыши на элементе.
  • mousemove – при движении мыши.

События на элементах управления:

  • submit – пользователь отправил форму <form> .
  • focus – пользователь фокусируется на элементе, например нажимает на <input> .

Клавиатурные события:

  • keydown и keyup – когда пользователь нажимает / отпускает клавишу.

События документа:

  • DOMContentLoaded – когда HTML загружен и обработан, DOM документа полностью построен и доступен.

CSS events:

Существует множество других событий. Мы подробно разберём их в последующих главах.

Обработчики событий

Событию можно назначить обработчик, то есть функцию, которая сработает, как только событие произошло.

Именно благодаря обработчикам JavaScript-код может реагировать на действия пользователя.

Есть несколько способов назначить событию обработчик. Сейчас мы их рассмотрим, начиная с самого простого.

Использование атрибута HTML

Обработчик может быть назначен прямо в разметке, в атрибуте, который называется on<событие> .

Например, чтобы назначить обработчик события click на элементе input , можно использовать атрибут onclick , вот так:

При клике мышкой на кнопке выполнится код, указанный в атрибуте onclick .

Обратите внимание, для содержимого атрибута onclick используются одинарные кавычки, так как сам атрибут находится в двойных. Если мы забудем об этом и поставим двойные кавычки внутри атрибута, вот так: onclick="alert("Click!")" , код не будет работать.

Атрибут HTML-тега – не самое удобное место для написания большого количества кода, поэтому лучше создать отдельную JavaScript-функцию и вызвать её там.

Следующий пример по клику запускает функцию countRabbits() :

Как мы помним, атрибут HTML-тега не чувствителен к регистру, поэтому ONCLICK будет работать так же, как onClick и onCLICK … Но, как правило, атрибуты пишут в нижнем регистре: onclick .

Использование свойства DOM-объекта

Можно назначать обработчик, используя свойство DOM-элемента on<событие> .

К примеру, elem.onclick :

Если обработчик задан через атрибут, то браузер читает HTML-разметку, создаёт новую функцию из содержимого атрибута и записывает в свойство.

Этот способ, по сути, аналогичен предыдущему.

Обработчик всегда хранится в свойстве DOM-объекта, а атрибут – лишь один из способов его инициализации.

Эти два примера кода работают одинаково:

Так как у элемента DOM может быть только одно свойство с именем onclick , то назначить более одного обработчика так нельзя.

В примере ниже назначение через JavaScript перезапишет обработчик из атрибута:

Кстати, обработчиком можно назначить и уже существующую функцию:

Убрать обработчик можно назначением elem.onclick = null .

Доступ к элементу через this

Внутри обработчика события this ссылается на текущий элемент, то есть на тот, на котором, как говорят, «висит» (т.е. назначен) обработчик.

В коде ниже button выводит своё содержимое, используя this.innerHTML :

Частые ошибки

Если вы только начинаете работать с событиями, обратите внимание на следующие моменты.

Функция должна быть присвоена как sayThanks , а не sayThanks() .

Если добавить скобки, то sayThanks() – это уже вызов функции, результат которого (равный undefined , так как функция ничего не возвращает) будет присвоен onclick . Так что это не будет работать.

…А вот в разметке, в отличие от свойства, скобки нужны:

Это различие просто объяснить. При создании обработчика браузером из атрибута, он автоматически создаёт функцию с телом из значения атрибута: sayThanks() .

Так что разметка генерирует такое свойство:

Используйте именно функции, а не строки.

Назначение обработчика строкой elem.onclick = "alert(1)" также сработает. Это сделано из соображений совместимости, но делать так не рекомендуется.

Не используйте setAttribute для обработчиков.

Такой вызов работать не будет:

Регистр DOM-свойства имеет значение.

Используйте elem.onclick , а не elem.ONCLICK , потому что DOM-свойства чувствительны к регистру.

addEventListener

Фундаментальный недостаток описанных выше способов назначения обработчика – невозможность повесить несколько обработчиков на одно событие.

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

Разработчики стандартов достаточно давно это поняли и предложили альтернативный способ назначения обработчиков при помощи специальных методов addEventListener и removeEventListener . Они свободны от указанного недостатка.

Синтаксис добавления обработчика:

  • once : если true , тогда обработчик будет автоматически удалён после выполнения.
  • capture : фаза, на которой должен сработать обработчик, подробнее об этом будет рассказано в главе Всплытие и погружение. Так исторически сложилось, что options может быть false/true , это то же самое, что .
  • passive : если true , то указывает, что обработчик никогда не вызовет preventDefault() , подробнее об этом будет рассказано в главе Действия браузера по умолчанию.

Для удаления обработчика следует использовать removeEventListener :

Для удаления нужно передать именно ту функцию-обработчик которая была назначена.

Вот так не сработает:

Обработчик не будет удалён, т.к. в removeEventListener передана не та же функция, а другая, с одинаковым кодом, но это не важно.

Вот так правильно:

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

Метод addEventListener позволяет добавлять несколько обработчиков на одно событие одного элемента, например:

Как видно из примера выше, можно одновременно назначать обработчики и через DOM-свойство и через addEventListener . Однако, во избежание путаницы, рекомендуется выбрать один способ.

Обработчики некоторых событий можно назначать только через addEventListener

Существуют события, которые нельзя назначить через DOM-свойство, но можно через addEventListener .

Например, таково событие DOMContentLoaded , которое срабатывает, когда завершена загрузка и построение DOM документа.

Так что addEventListener более универсален. Хотя заметим, что таких событий меньшинство, это скорее исключение, чем правило.

Объект события

Чтобы хорошо обработать событие, могут понадобиться детали того, что произошло. Не просто «клик» или «нажатие клавиши», а также – какие координаты указателя мыши, какая клавиша нажата и так далее.

Когда происходит событие, браузер создаёт объект события, записывает в него детали и передаёт его в качестве аргумента функции-обработчику.

Пример ниже демонстрирует получение координат мыши из объекта события:

Некоторые свойства объекта event :

event.type Тип события, в данном случае "click" . event.currentTarget Элемент, на котором сработал обработчик. Значение – обычно такое же, как и у this , но если обработчик является функцией-стрелкой или при помощи bind привязан другой объект в качестве this , то мы можем получить элемент из event.currentTarget . event.clientX / event.clientY Координаты курсора в момент клика относительно окна, для событий мыши.

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

При назначении обработчика в HTML, тоже можно использовать объект event , вот так:

Это возможно потому, что когда браузер из атрибута создаёт функцию-обработчик, то она выглядит так: function(event) < alert(event.type) >. То есть, её первый аргумент называется "event" , а тело взято из атрибута.

Объект-обработчик: handleEvent

Мы можем назначить обработчиком не только функцию, но и объект при помощи addEventListener . В этом случае, когда происходит событие, вызывается метод объекта handleEvent .

Как видим, если addEventListener получает объект в качестве обработчика, он вызывает object.handleEvent(event) , когда происходит событие.

Мы также можем использовать класс для этого:

Здесь один и тот же объект обрабатывает оба события. Обратите внимание, мы должны явно назначить оба обработчика через addEventListener . Тогда объект menu будет получать события mousedown и mouseup , но не другие (не назначенные) типы событий.

Метод handleEvent не обязательно должен выполнять всю работу сам. Он может вызывать другие методы, которые заточены под обработку конкретных типов событий, вот так:

Теперь обработка событий разделена по методам, что упрощает поддержку кода.

Итого

Есть три способа назначения обработчиков событий:

  1. Атрибут HTML: onclick=". " .
  2. DOM-свойство: elem.onclick = function .
  3. Специальные методы: elem.addEventListener(event, handler[, phase]) для добавления, removeEventListener для удаления.

HTML-атрибуты используются редко потому, что JavaScript в HTML-теге выглядит немного странно. К тому же много кода там не напишешь.

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

Последний способ самый гибкий, однако нужно писать больше всего кода. Есть несколько типов событий, которые работают только через него, к примеру transitionend и DOMContentLoaded . Также addEventListener поддерживает объекты в качестве обработчиков событий. В этом случае вызывается метод объекта handleEvent .

Не важно, как вы назначаете обработчик – он получает объект события первым аргументом. Этот объект содержит подробности о том, что произошло.

Почему на земле нет кнопок браузера, запускающих собственные события!?

ОТВЕТЫ

Ответ 1

(Примечание. Согласно обратной связи Sharky, я включил код для обнаружения обратных пространств)

Большинство людей рекомендуют использовать:

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

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

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

Я также использую кнопку возврата на странице, которая перемещает пользователя между страницами с помощью массива lasthash . Это выглядит так:

Итак, это вернет пользователя к последнему хэшу и удалит последний хэш из массива (у меня нет прямой кнопки прямо сейчас).

Итак. Как определить, использовал ли пользователь мою кнопку возврата на странице или кнопку браузера?

Сначала я посмотрел на window.onbeforeunload , но безрезультатно - это только вызывается, если пользователь собирается менять страницы. Это не происходит в одностраничном приложении с использованием хэш-навигации.

Итак, после некоторого дополнительного копания, я увидел рекомендации по попытке установить переменную флага. Проблема с этим в моем случае заключается в том, что я попытаюсь установить его, но поскольку все будет асинхронным, оно не всегда будет установлено во времени для оператора if в изменении хэша. .onMouseDown не всегда вызывался кликом, а добавление его в onclick не вызывало бы его достаточно быстро.

Это когда я начал смотреть на разницу между document и window . Моим окончательным решением было установить флаг с помощью document.onmouseover и отключить его с помощью document.onmouseleave .

Что происходит, когда пользовательская мышь находится внутри области документа (читайте: отображаемая страница, но исключая рамку браузера), мое логическое значение имеет значение true . Как только мышь покидает область документа, логическое значение переворачивается до false .

Таким образом, я могу изменить свой window.onhashchange на:

Итак, короче говоря, для людей, которые не обязательно используют кнопку возврата на странице или массив для хранения истории:

И у вас это есть. простой, трехкомпонентный способ обнаружения использования кнопки обратной связи и элементов на странице в отношении хеш-навигации.

Чтобы гарантировать, что пользователь не будет использовать backspace для запуска события back, вы также можете включить следующее (Спасибо @thetoolman на этот вопрос):

Ответ 2

Вы можете попробовать popstate обработчик событий, например:

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

Событие popstate запускается каждый раз, когда изменяется текущая запись истории (пользователь переходит в новое состояние). Это происходит, когда пользователь нажимает кнопки браузера Back/Forward или когда методы history.back() , history.forward() , history.go() запрограммированы.

Свойство event.state является событием, равным объекту состояния истории.

Для синтаксиса jQuery оберните его (чтобы добавить даже слушателя после того, как документ готов):

Это должно быть совместимо с Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ и т.д.

Ответ 3

Я довольно долго боролся с этим требованием и принял некоторые из решений выше, чтобы реализовать его. Тем не менее, я наткнулся на наблюдение и, похоже, работает в браузерах Chrome, Firefox и Safari + Android и iPhone.

Загрузка на страницу:

Сообщите мне, если это поможет. Если я что-то упустил, я буду рад понять.

Ответ 4

В javascript тип навигации 2 означает, что браузер нажимает кнопку "назад" или "вперед", и браузер фактически берет контент из кэша.

Ответ 5

Это определенно будет работать (для обнаружения нажатия кнопки назад)

Ответ 6

Ответ 7

Вот мой взгляд на это. Предполагается, что при изменении URL-адреса, но не обнаружено клика внутри обнаруженного document , это браузер назад (да или вперед). Пользовательский щелчок reset через 2 секунды, чтобы сделать эту работу на страницах, загружающих контент через Ajax:

Ответ 8

добавил этот код внизу страницы. см. эту кнопку обнаружения браузера baa

Ответ 9

Ответ 10

Правильный ответ уже есть, чтобы ответить на вопрос. Я хочу упомянуть новый JavaScript API PerformanceNavigationTiming, он заменил устаревший performance.navigation.

Следующий код будет входить в консоль "back_forward", если пользователь зашел на вашу страницу с помощью кнопки назад или вперед. Посмотрите на таблицу совместимости, прежде чем использовать ее в своем проекте.

Ответ 11

document.mouseover не работает для IE и FireFox. Однако я пробовал это:

Это работает для Chrome и IE, а не для FireFox. Все еще работаю над тем, чтобы получить FireFox. Любой простой способ обнаружения щелчка мыши назад/вперед браузера приветствуется, особенно не в JQuery, а также в AngularJS или в простом Javascript.

Ответ 12

Ответ 13

Я смог использовать некоторые ответы в этой теме и другие, чтобы заставить его работать в IE и Chrome/Edge. history.pushState для меня не поддерживается в IE11.

Ответ 14

Ответ 15

Это единственное решение, которое сработало для меня (это не одностраничный сайт). Работает с Chrome, Firefox и Safari.

Ответ 16

Я пробовал вышеуказанные параметры, но ни один из них не работает для меня. Вот решение

Читайте также: