Dobry samouczek dotyczący korzystania z interfejsu API historii HTML5 (Pushstate?) [Zamknięty]

168

Zastanawiam się nad wykorzystaniem interfejsu API historii HTML5, aby rozwiązać problemy z linkowaniem głębokim w treściach ładowanych w formacie AJAX, ale nie mogę się doczekać rozpoczęcia pracy. Czy ktoś zna jakieś dobre zasoby?

Chcę to wykorzystać, ponieważ wydaje się to świetny sposób, aby pozwolić, aby wysyłane linki nie miały włączonego JS. Wiele rozwiązań zawodzi, gdy ktoś z JS wysyła link do kogoś bez.

Moje wstępne badania wydają się wskazywać na History API w JS i metodę pushState.

http://html5demos.com/history

Łagodny Fuzz
źródło

Odpowiedzi:

181

Aby uzyskać świetny samouczek, wystarczy strona Mozilla Developer Network dotycząca tej funkcji: https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history

Niestety interfejs API historii HTML5 jest zaimplementowany w różny sposób we wszystkich przeglądarkach HTML5 (co powoduje, że jest niespójny i zawiera błędy) i nie ma funkcji zastępczej dla przeglądarek HTML4. Na szczęście History.js zapewnia wzajemną kompatybilność dla przeglądarek HTML5 (zapewniając, że wszystkie przeglądarki HTML5 działają zgodnie z oczekiwaniami) i opcjonalnie zapewnia zastępczą wartość skrótu dla przeglądarek HTML4 (w tym utrzymaną obsługę danych, tytułów, funkcji pushState i replaceState).

Możesz przeczytać więcej o History.js tutaj: https://github.com/browserstate/history.js

Aby zapoznać się z artykułem o Hashbangs VS Hashes VS HTML5 History API, zobacz tutaj: https://github.com/browserstate/history.js/wiki/Intelligent-State-Handling

balupton
źródło
25
Bezwstydna wtyczka własna. Doskonały post i wtyczka. :)
Purag
28

Pamiętaj, że podczas korzystania z pushstate HTML5, jeśli użytkownik skopiuje lub doda do zakładek głęboki link i odwiedzi go ponownie, będzie to bezpośrednie trafienie na serwer, które 404 spowoduje, że musisz być na to przygotowany, a nawet biblioteka pushstate js nie pomoże ty. Najłatwiejszym rozwiązaniem jest dodanie reguły przepisywania do serwera Nginx lub Apache w następujący sposób:

Apache (w twoim vhostie, jeśli go używasz):

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>

Nginx

rewrite ^(.+)$ /index.html last;
Mauvis Ledford
źródło
TO jest prawdziwa odpowiedź. Nie ma tego nigdzie na wiki / tutorialach Balupton History.js itp. W rzeczywistości History.js nie używa hasha, więc musisz użyć przekierowania .htaccess!
adriendenat
13
W idealnym przypadku serwer / aplikacja powinna odpowiednio reagować na trasę bez konieczności przepisywania.
sholsinger,
Zgoda, z wyjątkiem wielu nowoczesnych frameworków JavaScript, takich jak Backbone.js, Spine, Ember itp. Są to zasadniczo aplikacje JavaScript typu „jedna strona”. Można by wypracować rozwiązanie obsługujące szablon backendu zapisu dla SEO, itd., Ale w międzyczasie byłoby to konieczne.
Mauvis Ledford
*dobrze. Piszę o tym bardziej szczegółowo tutaj: readystate4.com/2012/05/17/…
Mauvis Ledford
6

Specyfikacja historii HTML5 jest dziwaczna.

history.pushState()nie wysyła popstatezdarzenia ani nie wczytuje samodzielnie nowej strony. Miało to tylko wprowadzić państwo do historii. Jest to funkcja „cofnij” dla aplikacji jednostronicowych. Musisz ręcznie wywołać popstatezdarzenie lub użyć, history.go()aby przejść do nowego stanu. Chodzi o to, że router może słuchać popstatezdarzeń i wykonywać nawigację za Ciebie.

Kilka uwag:

  • history.pushState()i history.replaceState()nie wysyłaj popstatewydarzeń.
  • history.back(), history.forward()a przyciski wstecz i dalej w przeglądarce wywołują popstatezdarzenia.
  • history.go()i history.go(0)przeładuj całą stronę i nie wysyłaj popstatezdarzeń.
  • history.go(-1)(wstecz 1 strona) i history.go(1)(dalej 1 strona) wysyłają popstatezdarzenia.

Możesz użyć interfejsu API historii w ten sposób, aby wypchnąć nowy stan ORAZ wywołać zdarzenie popstate.

history.pushState({message:'New State!'}, 'New Title', '/link'); window.dispatchEvent(new PopStateEvent('popstate', { bubbles: false, cancelable: false, state: history.state }));

Następnie nasłuchuj popstatezdarzeń za pomocą routera.

Erik Ringsmuth
źródło
1
Czy to tylko ja, czy new PopStateEvent(...)wydaje się, że nie działa w IE11? Czy istnieje obejście, o którym ktoś wie?
David Alan Hjelle
Wygląda na to, że IE 11 potrzebuje czegoś takiego: var pop_state_event = document.createEvent('Event'); pop_state_event.initEvent('popstate', true, true); window.dispatchEvent(pop_state_event);
David Alan Hjelle
4

Możesz wypróbować Davis.js , który zapewnia routing w JavaScript za pomocą pushState, gdy jest dostępny, a bez JavaScript pozwala kodowi po stronie serwera na obsługę żądań.

Oliver Nightingale
źródło
2

Możesz rzucić okiem na tę wtyczkę jQuery. Mają wiele przykładów na swojej stronie. http://www.asual.com/jquery/address/

Nathan Totten
źródło
Ponownie, to rozwiązanie nie działa, gdy JS jest wyłączony. Myślę, że interfejs API historii może działać w połączeniu z modrewrite, dzięki czemu linki są zawsze przetwarzane w pierwszej kolejności przez serwer, bez konieczności przekierowywania z warstwy JS.
Mild Fuzz
Z modrewrite jesteś na dobrej drodze. Rozwiązanie zarządzania historycznym API i obsługa, gdy użytkownik nie ma JS, to tak naprawdę dwie odrębne rzeczy. Jeśli nie masz JS, musisz obsłużyć użytkownika za pomocą standardowych hrefów i odpowiedzi serwera. History API można zbudować jako coś w rodzaju „miłego posiadania”, jeśli przeglądarka użytkownika go obsługuje.
Nathan Totten
Próbki Express i State dostarczane z adresem jQuery Address 1.3 działają dość dobrze, gdy JavaScript jest wyłączony. Drugi używa PHP z mod_rewrite.
Rostislav
Dokładnie mój takt. Zamierzam zbudować stronę bez JS, dodać elementy AJAX, a następnie użyć historii do przepisania adresu URL, zachowując głębokie linkowanie. Teoretycznie powinna to być lepsza metoda niż jakakolwiek inna, którą widziałem, ponieważ strona nie będzie zależała od AJAX, na żadnym etapie
Mild Fuzz
1
-1, ponieważ adres jQuery nie jest bezpośrednim portem interfejsu API stanu HTML5 - nie obsługuje danych ani tytułów i replaceState.
balupton
2

Napisałem bardzo prostą abstrakcję routera na podstawie History.js , nazwaną StateRouter.js . Jest na bardzo wczesnym etapie rozwoju, ale używam go jako rozwiązania routingu w aplikacji jednostronicowej, którą piszę. Tak jak ty, bardzo trudno mi było pojąć History.js, zwłaszcza że jestem całkiem nowy w JavaScript, dopóki nie zrozumiałem, że naprawdę potrzebujesz (lub powinieneś mieć) abstrakcję routingu, ponieważ rozwiązuje ona problem niskiego poziomu problem.

Ten prosty przykładowy kod powinien pokazać, jak jest używany:

var router = new staterouter.Router();
// Configure routes
router
  .route('/', getHome)
  .route('/persons', getPersons)
  .route('/persons/:id', getPerson);
// Perform routing of the current state
router.perform();

Oto małe skrzypce , które wymyśliłem, aby zademonstrować jego użycie.

aknuds1
źródło
1
To skrzypce nie działa dla mnie w Chrome na Macu. Zgłasza błąd. (Uncaught ReferenceError: staterouter nie jest zdefiniowany)
DrewT,
@DrewT Dzięki, skrzypce się zepsuły z powodu zmiany na github.com, ale udało mi się to obejść.
aknuds1
Tak, teraz pracuję, dzięki za szybką odpowiedź.
DrewT
1

jeśli jQuery jest dostępne, możesz użyć jQuery BBQ

sprugman
źródło
Wydaje się, że to się nie udaje, gdy JS jest wyłączony.
Mild Fuzz
to prawdopodobnie prawda - nie zaglądałem do tego. Myślę, że będziesz miał ten problem ze wszystkimi podejściami opartymi na bibliotekach js. Opierają się na manipulowaniu częścią skrótu adresu URL.
sprugman
1
o to właśnie chodzi w HTML5 History API - to niczego nie psuje
balupton
2
@MildFuzz Komputer wydaje się nie działać bez źródła zasilania! Myślę, że masz błąd ID-10-T ...
Eric Hodonsky
1
Jak na ironię, to ty źle zrozumiałeś
Mild Fuzz