Während # 2 für Sie als Entwickler "einfacher" sein könnte, bietet es nur Suchmaschinen-Crawlen. Und ja, wenn Google herausfindet, dass Sie unterschiedliche Inhalte bereitstellen, werden Sie möglicherweise bestraft (ich bin kein Experte dafür, aber ich habe davon gehört).
Sowohl SEO als auch Barrierefreiheit (nicht nur für behinderte Menschen, sondern auch Barrierefreiheit über mobile Geräte, Touchscreen-Geräte und andere nicht standardmäßige Computer- / internetfähige Plattformen) haben beide eine ähnliche Philosophie: semantisch reichhaltiges Markup, das "zugänglich" ist (dh kann) auf all diese verschiedenen Browser zugegriffen, angezeigt, gelesen, verarbeitet oder anderweitig verwendet werden. Ein Bildschirmleser, ein Suchmaschinen-Crawler oder ein Benutzer mit aktiviertem JavaScript sollte in der Lage sein, die Kernfunktionen Ihrer Website ohne Probleme zu verwenden / zu indizieren / zu verstehen.
pushState
trägt meiner Belastung nach meiner Erfahrung nicht bei. Es bringt nur das, was früher ein nachträglicher Gedanke war und "wenn wir Zeit haben", in den Vordergrund der Webentwicklung.
Was Sie in Option 1 beschreiben, ist normalerweise der beste Weg - aber wie bei anderen Problemen mit der Barrierefreiheit und der Suchmaschinenoptimierung pushState
erfordert dies in einer JavaScript-lastigen App eine Vorausplanung, da dies zu einer erheblichen Belastung wird. Es sollte von Anfang an in die Seiten- und Anwendungsarchitektur integriert werden - das Nachrüsten ist schmerzhaft und führt zu mehr Duplikaten als erforderlich.
Ich habe pushState
kürzlich mit und SEO für ein paar verschiedene Anwendungen gearbeitet und fand, was ich für einen guten Ansatz halte. Es folgt im Wesentlichen Ihrem Artikel Nr. 1, berücksichtigt jedoch, dass HTML / Vorlagen nicht dupliziert werden.
Die meisten Informationen finden Sie in diesen beiden Blog-Beiträgen:
http://lostechies.com/derickbailey/2011/09/06/test-driving-backbone-views-with-jquery-templates-the-jasmine-gem-and-jasmine-jquery/
und
http://lostechies.com/derickbailey/2011/06/22/rendering-a-rails-partial-as-a-jquery-template/
Das Wesentliche dabei ist, dass ich ERB- oder HAML-Vorlagen (mit Ruby on Rails, Sinatra usw.) für mein serverseitiges Rendern und zum Erstellen der clientseitigen Vorlagen verwende, die Backbone verwenden kann, sowie für meine Jasmine-JavaScript-Spezifikationen. Dies verhindert das Duplizieren von Markups zwischen der Serverseite und der Clientseite.
Von dort aus müssen Sie einige zusätzliche Schritte ausführen, damit Ihr JavaScript mit dem vom Server gerenderten HTML funktioniert - echte progressive Verbesserung; Nehmen Sie das gelieferte semantische Markup und erweitern Sie es mit JavaScript.
Zum Beispiel baue ich eine Bildergalerie-Anwendung mit pushState
. Wenn Sie dies /images/1
vom Server anfordern , wird die gesamte Bildergalerie auf dem Server gerendert und der gesamte HTML-, CSS- und JavaScript-Code an Ihren Browser gesendet. Wenn Sie JavaScript deaktiviert haben, funktioniert es einwandfrei. Jede Aktion, die Sie ausführen, fordert eine andere URL vom Server an und der Server rendert das gesamte Markup für Ihren Browser. Wenn Sie jedoch JavaScript aktiviert haben, nimmt das JavaScript den bereits gerenderten HTML-Code zusammen mit einigen vom Server generierten Variablen auf und übernimmt von dort aus.
Hier ist ein Beispiel:
<form id="foo">
Name: <input id="name"><button id="say">Say My Name!</button>
</form>
Nachdem der Server dies gerendert hat, nimmt das JavaScript es auf (in diesem Beispiel mithilfe der Ansicht Backbone.js).
FooView = Backbone.View.extend({
events: {
"change #name": "setName",
"click #say": "sayName"
},
setName: function(e){
var name = $(e.currentTarget).val();
this.model.set({name: name});
},
sayName: function(e){
e.preventDefault();
var name = this.model.get("name");
alert("Hello " + name);
},
render: function(){
// do some rendering here, for when this is just running JavaScript
}
});
$(function(){
var model = new MyModel();
var view = new FooView({
model: model,
el: $("#foo")
});
});
Dies ist ein sehr einfaches Beispiel, aber ich denke, es bringt den Punkt auf den Punkt.
Wenn ich die Ansicht nach dem Laden der Seite instanziiere, stelle ich der Ansichtsinstanz den vorhandenen Inhalt des vom Server gerenderten Formulars als el
für die Ansicht bereit. Ich rufe nicht rendern auf oder lasse die Ansicht el
für mich generieren , wenn die erste Ansicht geladen wird. Ich habe eine Rendermethode zur Verfügung, nachdem die Ansicht ausgeführt wurde und die Seite ausschließlich aus JavaScript besteht. Auf diese Weise kann ich die Ansicht später bei Bedarf erneut rendern.
Wenn Sie bei aktiviertem JavaScript auf die Schaltfläche "Sag meinen Namen" klicken, wird ein Warnfeld angezeigt. Ohne JavaScript würde es auf den Server zurückgesendet und der Server könnte den Namen irgendwo in ein HTML-Element rendern.
Bearbeiten
Stellen Sie sich ein komplexeres Beispiel vor, in dem Sie eine Liste haben, die angehängt werden muss (aus den Kommentaren darunter).
Angenommen, Sie haben eine Liste von Benutzern in einem <ul>
Tag. Diese Liste wurde vom Server gerendert, als der Browser eine Anfrage stellte, und das Ergebnis sieht ungefähr so aus:
<ul id="user-list">
<li data-id="1">Bob
<li data-id="2">Mary
<li data-id="3">Frank
<li data-id="4">Jane
</ul>
Jetzt müssen Sie diese Liste durchlaufen und jedem <li>
Element eine Backbone-Ansicht und ein Backbone-Modell hinzufügen. Mithilfe des data-id
Attributs können Sie leicht das Modell finden, von dem jedes Tag stammt. Sie benötigen dann eine Sammlungsansicht und eine Elementansicht, die intelligent genug sind, um sich an dieses HTML anzuhängen.
UserListView = Backbone.View.extend({
attach: function(){
this.el = $("#user-list");
this.$("li").each(function(index){
var userEl = $(this);
var id = userEl.attr("data-id");
var user = this.collection.get(id);
new UserView({
model: user,
el: userEl
});
});
}
});
UserView = Backbone.View.extend({
initialize: function(){
this.model.bind("change:name", this.updateName, this);
},
updateName: function(model, val){
this.el.text(val);
}
});
var userData = {...};
var userList = new UserCollection(userData);
var userListView = new UserListView({collection: userList});
userListView.attach();
In diesem Beispiel UserListView
werden alle <li>
Tags durchlaufen und ein Ansichtsobjekt mit dem richtigen Modell für jedes angehängt. Es richtet einen Ereignishandler für das Ereignis zur Namensänderung des Modells ein und aktualisiert den angezeigten Text des Elements, wenn eine Änderung auftritt.
Diese Art von Prozess, um das vom Server gerenderte HTML zu übernehmen und mein JavaScript übernehmen und ausführen zu lassen, ist eine großartige Möglichkeit, die Dinge für SEO, Barrierefreiheit und pushState
Support ins Rollen zu bringen .
Hoffentlich hilft das.