Więc teraz, kiedy HTML5 wprowadza history.pushState
zmianę historii przeglądarek, strony internetowe zaczynają używać tego w połączeniu z Ajaxem zamiast zmieniać identyfikator fragmentu adresu URL.
Niestety oznacza to, że te połączenia nie mogą być już wykrywane przez onhashchange
.
Moje pytanie brzmi: czy istnieje niezawodny sposób (włamanie?;)) Do wykrycia, kiedy witryna używa history.pushState
? Specyfikacja nie mówi nic o zdarzeniach, które są wywoływane (przynajmniej nie mogłem nic znaleźć).
Próbowałem stworzyć fasadę i zastąpiłem window.history
go własnym obiektem JavaScript, ale nie przyniosło to żadnego efektu.
Dalsze wyjaśnienie: opracowuję dodatek do Firefoksa, który musi wykrywać te zmiany i odpowiednio działać.
Wiem, że kilka dni temu było podobne pytanie, które dotyczyło tego, czy odsłuchiwanie niektórych zdarzeń DOM byłoby wydajne, ale wolałbym nie polegać na tym, ponieważ zdarzenia te mogą być generowane z wielu różnych powodów.
Aktualizacja:
Oto jsfiddle (użyj przeglądarki Firefox 4 lub Chrome 8), który pokazuje, że onpopstate
nie jest uruchamiany, gdy pushState
jest wywoływany (czy robię coś źle? Możesz to poprawić!).
Aktualizacja 2:
Innym (bocznym) problemem jest to, że window.location
nie jest aktualizowany podczas używania pushState
(ale o tym czytałem już tutaj na SO tak myślę).
źródło
history
przedmiot. W tym przypadku może to być niepotrzebne.window.history
jest tylko do odczytu, ale właściwości obiektu historii nie są ... Dzięki pęczek dla tego rozwiązania :)pushState
metodę do późniejszego wykorzystania. Więc zamiast zmiennej globalnej zdecydowałem się zamknąć cały kod w IIFE: en.wikipedia.org/wiki/Immediately-invoked_function_expressionUżywałem tego:
To prawie to samo, co galambalazs .
Zwykle jest to jednak przesada. I może nie działać we wszystkich przeglądarkach. (Dbam tylko o wersję mojej przeglądarki).
(I pozostawia var
_wr
, więc możesz chcieć to opakować czy coś. Nie obchodziło mnie to).źródło
Wreszcie znalazłem „właściwy” sposób, aby to zrobić! Wymaga dodania uprawnienia do rozszerzenia i korzystania ze strony w tle (nie tylko skryptu zawartości), ale działa.
Wybranym zdarzeniem
browser.webNavigation.onHistoryStateUpdated
jest wywoływane, gdy strona używahistory
interfejsu API do zmiany adresu URL. Uruchamia się tylko w przypadku witryn, do których masz uprawnienia dostępu, a jeśli zajdzie taka potrzeba, możesz również użyć filtru adresów URL, aby jeszcze bardziej ograniczyć spam. WymagawebNavigation
pozwolenia (i oczywiście pozwolenia hosta dla odpowiednich domen).Wywołanie zwrotne zdarzenia pobiera identyfikator karty, adres URL, do którego następuje „nawigacja”, i inne tego typu szczegóły. Jeśli musisz wykonać jakąś czynność w skrypcie zawartości na tej stronie, gdy zdarzenie się uruchamia, albo wstrzyknij odpowiedni skrypt bezpośrednio ze strony w tle, albo otwórz skrypt zawartości na
port
stronę w tle po załadowaniu, zapisz stronę w tle ten port w kolekcji indeksowany przez identyfikator karty i wysyła komunikat przez odpowiedni port (ze skryptu działającego w tle do skryptu zawartości), gdy zdarzenie zostanie uruchomione.źródło
Mógłbyś związać się z
window.onpopstate
wydarzeniem?https://developer.mozilla.org/en/DOM%3awindow.onpopstate
Z dokumentów:
źródło
history.go
,.back
) funkcje są wywoływane. Ale nie włączonepushState
. Oto moja próba przetestowania, być może zrobię coś złego: jsfiddle.net/fkling/vV9vd Wydaje się, że jest to powiązane tylko w ten sposób, że jeśli historia została zmieniona przezpushState
, odpowiedni obiekt stanu jest przekazywany do obsługi zdarzeń, gdy inne metody są nazywane.Ponieważ pytasz o dodatek do Firefoksa, oto kod, który mam do pracy. Używanie nie
unsafeWindow
jest już zalecane , a błędy są wyświetlane, gdy pushState jest wywoływana ze skryptu klienta po modyfikacji:Zamiast tego istnieje interfejs API o nazwie exportFunction, który umożliwia wstrzyknięcie funkcji w
window.history
następujący sposób:źródło
unsafeWindow.history,
nawindow.history
. Nie działało to dla mnie z unsafeWindow.galambalazs w odpowiedzi małpie łatki
window.history.pushState
iwindow.history.replaceState
, ale z jakiegoś powodu przestał działać dla mnie. Oto alternatywa, która nie jest tak przyjemna, ponieważ wykorzystuje odpytywanie:źródło
Myślę, że ten temat wymaga bardziej nowoczesnego rozwiązania.
Jestem pewien, że wtedy
nsIWebProgressListener
był w pobliżu, jestem zaskoczony, że nikt o tym nie wspomniał.Ze skryptu ramek (dla zgodności z e10s):
Następnie słuchaj w
onLoacationChange
To najwyraźniej złapie wszystkie pushState. Ale jest komentarz ostrzegający, że "RÓWNIEŻ wyzwala pushState". Musimy więc trochę więcej filtrować, aby upewnić się, że to tylko rzeczy pushstate.
Na podstawie: https://github.com/jgraham/gecko/blob/55d8d9aa7311386ee2dabfccb481684c8920a527/toolkit/modules/addons/WebNavigation.jsm#L18
Oraz: resource: //gre/modules/WebNavigationContent.js
źródło
Cóż, widzę wiele przykładów zamiany
pushState
właściwości,history
ale nie jestem pewien, czy to dobry pomysł, wolałbym utworzyć zdarzenie usługi oparte na podobnym API do historii, aby można było kontrolować nie tylko stan wypychania, ale także stan zastępowania również i otwiera drzwi dla wielu innych implementacji, które nie opierają się na globalnym API historii. Proszę sprawdzić następujący przykład:Jeśli potrzebujesz
EventEmitter
definicji, powyższy kod jest oparty na emiterze zdarzeń NodeJS: https://github.com/nodejs/node/blob/36732084db9d0ff59b6ce31e839450cd91a156be/lib/events.js .utils.inherits
implementację można znaleźć tutaj: https://github.com/nodejs/node/blob/36732084db9d0ff59b6ce31e839450cd91a156be/lib/util.js#L970źródło
Wolałbym nie nadpisywać natywnej metody historii, więc ta prosta implementacja tworzy moją własną funkcję o nazwie eventedPush, która po prostu wywołuje zdarzenie i zwraca history.pushState (). Tak czy inaczej działa dobrze, ale uważam, że ta implementacja jest nieco czystsza, ponieważ metody natywne będą nadal działać zgodnie z oczekiwaniami przyszłych programistów.
źródło
W oparciu o rozwiązanie podane przez @gblazex , jeśli chcesz zastosować to samo podejście, ale używając funkcji strzałek, postępuj zgodnie z poniższym przykładem w logice javascript:
Następnie zaimplementuj inną funkcję,
_notifyUrl(url)
która wyzwala wszelkie wymagane działania, których możesz potrzebować, gdy aktualny adres URL strony zostanie zaktualizowany (nawet jeśli strona nie została w ogóle załadowana)źródło
Ponieważ chciałem tylko nowego adresu URL, dostosowałem kody @gblazex i @Alberto S., aby uzyskać to:
źródło
Nie sądzę, aby modyfikowanie funkcji natywnych, nawet jeśli jest to możliwe, nie jest dobrym pomysłem i zawsze należy zachować zakres aplikacji, więc dobrym podejściem jest nie używanie funkcji globalnej pushState, zamiast tego użyj jednej z własnych:
Zauważ, że jeśli jakikolwiek inny kod używa natywnej funkcji pushState, nie otrzymasz wyzwalacza zdarzenia (ale jeśli tak się stanie, powinieneś sprawdzić swój kod)
źródło
Standardowo stwierdza:
musimy wywołać history.back (), aby wywołać WindowEventHandlers.onpopstate
Więc zamiast:
robić:
źródło