Ajax-OnePage - Inhalt richtig per Ajax nachladen

Ajax-OnePage - Inhalt richtig per Ajax nachladen
Von Lars Ebert am 14.05.12, 11:00
Kategorien: JavaScript, jQuery, PHP, Programmieren and Tutorials

Immer wieder stolpere ich im Netz über Ajax-OnePages, also Seiten, bei denen, sobald man auf einen internen Link klickt, der gewünschte Inhalt per Ajax nachgeladen wird. Dadurch werden oft interessante Animationen, wie zum Beispiel Diashow-Übergänge oder Ähnliches möglich. Leider führt das Nachladen von Inhalten per Ajax, wenn man es nicht richtig macht, zu einer riesigen Katastrophe: keine Suchmaschine indiziert den nachgeladenen Inhalt und ohne JavaScript wird die Seite gänzlich unbrauchbar für den Nutzer.

In diesem Artikel will ich deshalb zeigen, wie man eine Ajax-OnePage richtig umsetzt und die zahlreichen Stolpersteine umgeht.

Der Schlüssel zum Erfolg liegt im Progressive Enhancement. Ohne JavaScript und Ajax funktioniert die Seite ganz normal, erst mit dem JavaScript kommen Animationen und OnePage-Charakteristika hinzu. So ist die Seite für jeden nutzbar und auch Suchmaschinen können den gesamten Inhalt indizieren.

Schritt 1: Vorbereitung - die Inhalte

Zunächst müssen wir jedoch ein paar Grundlagen schaffen. Zum Beispiel müssen wir jQuery herunterladen und eine HTML-Struktur erstellen. Mein Beispieldesign ist sehr — nun ja — brachial, aber ich will ja auch nur ein Konzept demonstrieren. Deshalb komme ich auch komplett ohne CSS aus.

Als erstes brauchen wir zwei Ordner js und pages. Im JS-Ordner liegt nur die Datei main.js, diese ist jedoch leer. In dem Ordner pages sollen später die Inhalte der Seite liegen. Für jede Unterseite sollte es hier eine Datei geben.

Ich lege hier erst einmal nur drei Dateien, also drei Unterseiten an.


<h1>Kontaktieren</h1>

<p>Hier könnte dein Kontakt-Formular stehen ;)</p>

<h1>Impressum</h1>

<p>Im Impressum stehen wichtige Daten, normalerweise jedenfalls&hellip;</p>


<h1>Hereinspaziert!</h1>

<p>Dies ist die Startseite - mehr Text brauchen wir nicht!</p>

Im Ernstfall würde man natürlich mehr Dateien und auch viel mehr Inhalt abspeichern, aber für meine kurze Demonstration sollen diese kurzen Texte genügen.

Schritt 2: Inhalte anzeigen

Nun müssen wir noch eine Datei index.php im Hauptordner anlegen. Hier findet sich später der HTML-Code, der auf allen Seiten gleich ist.


<?php
	
	$titles = array(
		'index' => 'Startseite',
		'contact' => 'Kontakt',
		'impressum' => 'Impressum'
	);
	
	$page = 'index';
	
	echo '<?xml version="1.0" encoding="UTF-8" ?>'; 
?>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<title><?php echo $titles[$page]; ?> - Ajax-OnePage</title>
	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>

<body>
	<header>
		Hier könnte ein Header stehen...
	</header>
	<nav>
		<ul>
			<?php
				foreach($titles as $key => $title) {
					echo '
			<li>
				<a href="' . $key . '.php" class="onPage">' . $title . '</a>
			</li>';
				}
			?>
		</ul>
	</nav>
	<div id="swapper"><?php include('pages/' . $page . '.page.php'); ?></div>
	<footer>
		Hallo, ich bin der Footer. Ich bleibe immer hier, egal wie du durch die Seite navigierst...
	</footer>
</body>

</html>

Hier definieren wir zuerst ein Array mit allen erlaubten Unterseiten, bestehend aus dem Dateinahmen (ohne Endung) und dem Seitentitel. Vorerst setzen wir die Variable $page auf index, also unsere Startseite. Anschließend folgt der HTML-Code. Hier wird automatisch der richtige Seitentitel und Inhalt eingefügt. Der Seitentitel wird aus dem Array genommen, der Inhalt wird aus der entsprechenden Datei im Ordner pages inkludiert. Als nächstes sorgen wir dafür, dass der Aufruf der Seiten contact.php und impressum.php auch auf index.php führt.

Schritt 3: Alle Aufrufe umleiten

Dazu legen wir die Datei .htaccess im Stammverzeichnis an. Hier können wir nun definieren, dass alle Aufrufe an die Webseite an index.php weitergeleitet werden.


<IfModule mod_rewrite.c>

# Enable URL rewriting
RewriteEngine On

#RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l

# Main URL rewriting.
RewriteRule .* index.php [L]

</IfModule>

Nun müssen wir in der Datei index.php noch dafür sorgen, dass auch die richtige Unterseite geladen wird. Statt die Variable $page manuell zu setzen, nutzen wir nun folgenden Code, um die gewünschte Unterseite auszuwählen.


$urlParts = array();
preg_match('/\/([a-z]+)\.php(\?.*)?$/', $_SERVER["REQUEST_URI"], $urlParts);

if(isset($urlParts[1]) && isset($titles[$urlParts[1]])) {
	$page = $urlParts[1];
} else {
	$page = 'index';
}

Was passiert hier? Zunächst wird mithilfe eines Regulären Ausdrucks die aufgerufene Url auseinandergenommen. Danach finden wir in $urlParts[1] den entsprechenden Dateinamen (wieder ohne Erweiterung).

Jetzt wird automatisch, wenn wir eine URL aufrufen, der entsprechende Inhalt aus dem Ordner pages geladen. Unsere Seite funktioniert also, und so wie sie ist, können Suchmaschinen auch sämtlichen Inhalt indizieren. Jede Seite hat eine eigene, gültige URL.

Schritt 4: Progressive Enhancement mit JavaScript

Nun geht es daran, aus unserer Seite mit ein wenig JavaScript eine OnePage-Seite zu zaubern.

Deshalb fügen wir zuerst folgenden Code in den Kopf des HTML-Codes in der Datei index.php ein.


<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
	/* <![CDATA[ */
		var titles = <?php echo json_encode($titles); ?>;
	/* ]> */
</script>
<script type="text/javascript" src="js/main.js"></script>

Wir laden also jQuery, übertragen unsere Seitentitel aus dem PHP-Code in eine JavaScript-Variable und laden unsere eigene JavaScript-Datei main.js. Diese Datei bearbeiten wir als nächstes.


function bindLinks(links) {
	links.click(function() {
		var href = $(this).attr('href');
		var page = href.substr(0, href.indexOf('.'));
		
		if(page == '') {
		    page = 'index';
		}
		
		changePage(page);
		
		return false;
	});
}

function changePage(page) {
	$.ajax('pages/' + page + '.page.php', {
		success: function(data) {
			$('title').text(titles[page] + ' - Ajax-OnePage');
			$('#swapper').html(data);
			bindLinks($('#swapper a.onPage'));
		}
	});
}

$(document).ready(function() {
	bindLinks($('a.onPage'));
});

Wir definieren zuerst eine Funktion bindLinks, die an Links den onClick-Event-Handler anfügt. In diesem Handler lesen wir aus dem Href-Attribut des Links die Zielseite aus und übergeben diese an die Funktion changePage. Hier starten wir einen Ajax-Request an die entsprechende Datei im Ordner pages. Sobald die Antwort vom Server kommt, ändern wir Titel und Inhalt der aktuellen Seite. Zusätzlich rufen wir noch einmal die Funktion bindLinks auf, falls im Inhalt der neuen Seite auch Links auftauchen.

Der Zaubertrick funktioniert perfekt: der Inhalt und der Titel der Seite werden ausgetauscht und der Nutzer muss die Seite nicht neu laden. Die Ajax-OnePage ist fertig.

Naja, leider noch nicht ganz, denn eine Kleinigkeit fällt noch auf: die URL wird nicht geändert. Hier bleibt alles beim Alten. Das zerstört nicht nur die Illusion, es raubt dem Nutzer außerdem die Zurück- und Refresh-Buttons des Browsers. Denn laden wir die Seite neu, landen wir wieder auf der ersten Seite, die wir aufgerufen haben. Der Zurück-Button bleibt sogar ganz ohne Funktionalität.

Schritt 5: Manipulation der Browser-History

Um dieses Problem zu lösen, verändern wir unser JavaScript noch ein wenig und nutzen die HTML5-History-API. Mit dieser können wir dem Browser-Verlauf einfach neue Einträge hinzufügen.


function bindLinks(links) {
	links.click(function() {
		var href = $(this).attr('href');
		var page = href.substr(0, href.indexOf('.'));
		
		changePage(page, true);
		
		return false;
	});
}

function changePage(page, forward) {
	$.ajax('pages/' + page + '.page.php', {
		success: function(data) {
			$('title').text(titles[page] + ' - Ajax-OnePage');
			$('#swapper').html(data);
			bindLinks($('#swapper a.onPage'));
			
			if(forward) {
				history.pushState('', titles[page] + ' - Ajax-OnePage', 'http://localhost/kleines/ajax-onepage/' + page + '.php');
			}
		}
	});
}

$(document).ready(function() {
	bindLinks($('a.onPage'));
	
	$(window).bind('popstate', function(event) {
		var rawFileName = window.location.href.match(/\/([a-z]+)\.php(\?.*)?$/);
		
		changePage(rawFileName[1], false);
	});
});

Wir müssen einfach dem Browser-Verlauf jedes Mal eine neue Seite hinzufügen, wenn wir die Seite wechseln, indem wir auf einen Link klicken.

Der neue Parameter von changePage definiert hier, ob wir uns normal durch die Seite bewegen (true) oder den Zurück-Button des Browsers nutzen (false). Denn wenn wir den Zurück-Button des Browsers klicken, darf natürlich die Seite nicht als neue Seite eingetragen werden, denn sie ist ja nicht neu.

Wenn wir uns also normal durch die Seite bewegen, wird mit history.pushState('', titles[page] + ' - Ajax-OnePage', 'http://localhost/kleines/ajax-onepage/' + page + '.php'); ein neuer Eintrag in der History gespeichert. Der zweite Parameter definiert hierbei den Seitentitel und der dritte Parameter die URL der neuen Seite.

Mit $(window).bind('popstate' .... reagieren wir auf das betätigen des Zurück-Buttons. Denn dann muss die vorherige Seite geladen werden.

Fazit: Perfekte Illusion

Nun ist der Zauber wirklich perfekt, die Seite kann jetzt mit und ohne JavaScript durch die Seite navigieren und selbst Suchmaschinen finden den gesamten Inhalt. Trotzdem kommt die gesamte Seite im Idealfall aus, ohne auch nur ein einziges Mal die Seite neu zu laden. So macht man Ajax-OnePages richtig!

Und was sagst du?

Wie findest du die verwendete Technik? Ist alles klar geworden? Gib mir in den Kommentaren ein Feedback!