Rethinking Dynamic Page Replacing Content

Avatar of Jesse Shawl
Jesse Shawl on

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

The following is a guest post by Jesse Shawl.

In May of 2012, Chris updated a previous post about dynamic page replacing content. This article is an update to that update, which uses the HTML5 history API for a better user experience.

Here’s a quick recap of the best practices

  1. Works fine with JavaScript disabled.
  2. It is possible to "deep link" to specific content.
  3. The browsers back button and forward button work as expected.

Das Problem mit URL-Hashes

Für einen einzelnen Benutzer erfüllt die vorhandene Demo die Kriterien, aber URLs sind dauerhafte Adressen und werden geteilt.

Betrachten Sie das folgende Szenario

  1. Ich habe einen schicken Browser mit aktiviertem Javascript. Ich surfe auf der Demoseite und finde ein tolles Produkt, das ich mit einem Freund teilen möchte.
  2. Ich kopiere die URL "http://example.com/#awesome-product" und schicke sie meinem Freund.
  3. Mein Freund hat kein Javascript aktiviert. Sie öffnet den Link in ihrem Browser und ist verwirrt, dass das tolle Produkt nicht wie erwartet geladen wird.
  4. Sie ist verwirrt/frustriert und schwört, example.com nie wieder zu besuchen!

DAS IST SCHLECHTES UX!

Heute werden wir die bestehende Demo verbessern, sodass die dynamische Seiteninhaltsersetzung nicht auf den Hash angewiesen ist.

Demo ansehen   Dateien herunterladen

Modernizr für progressive Verbesserung

Hinweis: Die folgenden Beispiele bauen auf der vorherigen Demo auf. Laden Sie die Dateien hier herunter, um mitzumachen.

Wenn Sie Modernizr noch nicht verwenden, holen Sie es sich (ich warte). Es ist der einfachste Weg, Browserfunktionen mit JavaScript zu erkennen.

Da wir mit der HTML5-History-API herumspielen werden, müssen wir nur das Kontrollkästchen "History" aktivieren. Laden Sie den benutzerdefinierten Build hier herunter.

Fügen Sie ihn in den <head>-Bereich unserer HTML-Datei ein

<script src='js/modernizr.js'></script>

Der Test auf HTML5-History-Unterstützung ist super einfach

// dynamicpage.js

$(function() {
    if (Modernizr.history) {
        // history is supported; do magical things
    } else {
        // history is not supported; nothing fancy here
    }
});

Zuerst richten wir alles ein, um die Browserhistorie zu manipulieren, und fügen dann das schicke Laden aus der vorherigen Demo hinzu.

Die Historie mit der HTML5 History API manipulieren

Die HTML5-Methode history.pushState() ermöglicht es uns,

  1. die URL zu ändern
    • ohne Hash
    • ohne Seitenaktualisierung (hier findet die dynamische Inhaltsersetzung der Seite statt)
  2. den Browser-Historie-Stack zu aktualisieren
    • damit wir uns mit Klicks auf die Zurück- und Vorwärtstaste durch die Historie navigieren können.

Die pushState()-Methode nimmt drei Parameter entgegen

history.pushState(stateObject, "title", URL);

Wir werden in diesem Beispiel nur die URL übergeben, aber Sie können mehr über die History-API auf der Mozilla Developer Network erfahren.

Nachdem wir die URL geändert haben, werden wir eine Funktion zum Laden des Inhalts einrichten – loadContent() scheint ein guter Name zu sein.

$(function() {

  if (Modernizr.history) {

    // history is supported; do magical things

    // hijack the nav click event
    $("nav").delegate("a", "click", function() {

      _href = $(this).attr("href");

      // change the url without a page refresh and add a history entry.
      history.pushState(null, null, _href);

      // load the content
      loadContent(_href); // fear not! we're going to build this function in the next code block

    });

  } else {

    // history is not supported; nothing fancy here

  }

});

Und nun müssen wir nur noch die Funktion loadContent() programmieren, was eine Übernahme von Code aus dem ursprünglichen Beispiel ist.

Code-Dump

// set up some variables
var $mainContent = $("#main-content"),
    $pageWrap    = $("#page-wrap"),
    baseHeight   = 0,
    $el;

// calculate wrapper heights to prevent jumping when loading new content
$pageWrap.height($pageWrap.height());
baseHeight = $pageWrap.height() - $mainContent.height();

function loadContent(href) {

  $mainContent
    .find("#guts")
    .fadeOut(200, function() { // fade out the content of the current page
      $mainContent
        .hide()
        .load(href + " #guts", function() { // load the contents of whatever href is
          $mainContent.fadeIn(200, function() {
            $pageWrap.animate({
              height: baseHeight + $mainContent.height() + &quot;px&quot;
            });
         });
      
      $("nav a").removeClass("current");

      $("nav a[href$='" + href + "']").addClass("current");

    });

  });

}

Browser-Klicks auf Zurück- und Vorwärts-Buttons verarbeiten

Zu diesem Zeitpunkt wird der Inhalt auf schicke Weise per Ajax geladen, aber ein Klick auf den Zurück-Button bringt uns noch nicht zurück...

Die History-API gibt uns Zugriff auf das popstate-Ereignis, das jedes Mal ausgelöst wird, wenn sich der Historie-Stack ändert (lies: Zurück- und/oder Vorwärts-Buttons werden geklickt). Immer wenn dieses Ereignis ausgelöst wird, müssen wir nur unsere loadContent()-Funktion aufrufen.

$(window).bind("popstate", function() {
    link = location.pathname.replace(/^.*[\\/]/, ""); // get filename only
    loadContent(link);
});

Eine kleine Hausaufgabe

Zum Zeitpunkt des Schreibens tritt das popstate-Ereignis in Chrome beim Laden der Seite auf. Das bedeutet, es werden zwei Anfragen gestellt:

  1. Die ursprüngliche HTTP-Anfrage für wasauchimmer.html
  2. Die Anfrage von $.load in unserer loadContent()-Funktion

Es gibt ein paar verschiedene Möglichkeiten, damit umzugehen, aber ich überlasse Ihnen die Entscheidung, was am besten funktioniert.