Februar 2016

Band 31, Nummer 2

Dieser Artikel wurde maschinell übersetzt.

ASP.NET – Progressive Verbesserung mit ASP.NET und React

Durch Graham Mendick

Bereitstellen von Web-Inhalten zuverlässig ist Möglichkeit des Spiels. Die zufällige Elemente sind die Geschwindigkeit des Benutzers und Browserfunktionen. Progressive Verbesserung oder PE ist eine, die diese Unvorhersehbarkeit bietet. Das Herzstück der PE ist serverseitiges Rendering von HTML-Code. Es ist die einzige Möglichkeit, Ihre Verkaufschancen im Spiel der Inhaltsübermittlung zu maximieren. Für Benutzer mit einem modernen Browser Ebene auf JavaScript, um die zu verbessern.

Angesichts der Datenbindungsfunktion Bibliotheken wie AngularJS und Knockout wurde die Single-Page-Anwendung (SPA) einen eigenen. SPA ist die Antithesis von PE, da durch Wiedergeben der HTML-Client nicht vorhersagbar sind im Web ignoriert. Besucher in langsamen Netzwerken sind lange Ladezeiten, während Benutzer und Suchmaschinen mit weniger leistungsfähige Browsern keine Inhalte möglicherweise überhaupt erhalten. Aber auch diese Aspekte noch nicht die Vorteile des SPA Kanten.

Die SPA getötet progressive Verbesserung. Es war einfach zu schwierig, eine Server-gerenderten Anwendung in eine SPA über JavaScript-Erweiterung zu aktivieren.

Glücklicherweise stellt sich heraus, dass PE nicht wirklich inaktiv ist. Es ist nur aktiviert, und eine JavaScript-Bibliothek namens reagieren nur kommen und ihn reaktiviert. Reagieren bietet das beste aus beiden Welten, da es auf dem Server und auf dem Client ausgeführt werden kann. Sie können mit einer Server-gerenderten Anwendung starten und auf den Tastendruck, schalten Sie ihn zum Leben als Client gerendert.

Das Projekt TodoMVC (todomvc.com) bietet die gleichen Todo SPA mit anderen JavaScript-Bibliotheken Datenbindungsausdrücke erstellt um zu entscheiden. Eine hervorragende Projekt, vornehmen Implementierungen die vom Client-Rendering nur. In diesem Artikel platziere ich dieses Recht durch eine Ausschneiden-Down-Version als eine progressiv verbesserte SPA mit reagieren und ASP.NET erstellen. Ich werde auf die schreibgeschützte Funktionalität konzentrieren, sodass Sie die Liste der Todos anzeigen und filtern, um den aktiven anzeigen können oder solche abgeschlossen.

Rendering auf dem Server

Mit der alte Ansatz PE würde ich eine ASP.NET MVC-Anwendung mithilfe von Razor zum Rendern der Aufgabenliste auf dem Server erstellen. Wenn sie in eine SPA verbessern möchte, wäre ich wieder am – ich muss in JavaScript Renderinglogik erneut zu implementieren. Mit meinem neuen Ansatz für die PE erstelle ich eine ASP.NET MVC-Anwendung, die anstelle eines Razor zum Rendern der Aufgabenliste auf dem Server reagieren. Auf diese Weise können sie als Client-Renderingcode verdoppeln.

Ich beginne, indem Sie ein neues ASP.NET MVC-Projekt namens TodoMVC erstellen. Abgesehen von der View-Schicht der Code ist im Ordner Models eine TodoRepository enthält, die eine IEnumerable von Todos zurückgibt Primitiv, und innerhalb des HomeController wird eine Index-Methode, die in das Repository aufruft. Von diesem Zeitpunkt an starten Dinge etwas anders aussehen. Anstelle der Übergabe der Aufgabenliste für die Razor-Ansicht, werde ich es mit den HTML-Code auf dem Server zu übergeben.

JavaScript auf dem Server ausführen, die Sie benötigen Node.js, das Sie herunterladen können nodejs.org. Node.js enthält einen eigenen Paket-Manager namens Npm. Ich werde reagieren, die mithilfe von Npm, so wie ich NuGet zum Installieren eines Pakets .NET installieren. Ich werde ein Eingabeaufforderungsfenster, wechseln Sie zum Projektordner TodoMVC und führen Sie den Befehl "Npm Install reagieren".

Als Nächstes erstelle ich eine Datei namens app.jsx im Ordner Scripts (muss die jsx-Erweiterung in Kürze erläutert). Diese Datei wird der Renderinglogik reagieren, anstelle des Razor-Ansicht in einem normalen ASP.NET MVC-Projekt enthalten. Node.js verwendet ein System Laden von Modulen, zum Laden des Moduls reagieren, füge ich eine-Anweisung am Anfang der app.jsx erforderlich:

var React = require('react');

Eine reagieren-Benutzeroberfläche besteht aus Komponenten. Jede Komponente ist eine Render-Funktion, mit der Eingabe von Daten in HTML-Code wird. Die eingegebenen Daten werden als Eigenschaften übergeben. In app.jsx erstelle ich eine List-Komponente, die aus der Todos und gibt sie als ungeordnete Liste, den Titel des jedes Todo als ein Element dargestellt:

var List = React.createClass({
  render: function () {
    var todos = this.props.todos.map(function (todo) {
      return <li key={todo.Id}>{todo.Title}</li>;
    });
    return <ul>{todos}</ul>;
  }
});

Die Datei hat die Erweiterung jsx, da reagieren Code eine Mischung aus JavaScript und eine HTML-ähnliche Syntax JSX aufgerufen wird. Dieser Code auf dem Server ausgeführt werden soll, aber Node.js nicht versteht, JSX, sodass ich müssen zunächst die Datei in JavaScript umwandeln. Konvertieren von JSX in JavaScript als Transpiling bezeichnet wird, und ein Beispiel-Transpiler ist Babel. Ich konnte Meine app.jsx Inhalt fügen Sie in der online Babel Transpiler (babeljs.io/repl), und erstellen Sie eine Datei "App.js" aus der Transpiled-Ausgabe. Aber es ist jedoch sinnvoller, diesen Schritt automatisieren, da app.jsx recht häufig ändern könnte.

Dann schlucken verwende ich um die Konvertierung von app.jsx in app.js zu automatisieren. Dann schlucken ist ein JavaScript-aufgabenausführung, die mit einer Vielzahl von können Sie die Quelldateien transformieren-Plug-ins enthalten ist. Später schreibe ich einer Aufgabe schlucken, Bündel von JavaScript für den Browser. Im Moment benötige ich eine Aufgabe, die app.jsx über den Babel Transpiler übergibt, damit es in Node.js auf dem Server verwendet werden kann. Ich werde Gulp und den Babel-Plug-in von Npm durch Ausführen von installieren:

npm install gulp gulp-babel babel-preset-react

Wie Sie sehen können, indem die Paketnamen mit Leerzeichen zu trennen, kann ich mit einem einzigen Befehl mehrere Pakete installieren. Ich erstelle eine gulpfile.js sich im Projektordner TodoMVC und fügen Sie die Aufgabe Transpile hinzu:

var babel = require('gulp-babel');
gulp.task('transpile', function(){
  return gulp.src('Scripts/app.jsx')
    .pipe(babel({ presets: ['react'] }))
    .pipe(gulp.dest('Scripts/'))
});

Die Aufgabe besteht aus drei Schritten. Dann schlucken empfängt zunächst die app.jsx-Quelldatei. Anschließend wird die Datei über den Babel Transpiler weitergeleitet. Zuletzt wird die Datei app.js in die Scripts-Ordner gespeichert. Ausführbare erstellen möchten, verwende ich Editor zum Erstellen einer package.json-Datei im Projektordner TodoMVC mit Skripts Eintrag zeigen:

{
  "scripts": {
    "transpile": "gulp transpile"
  }
}

Über die Befehlszeile führe ich die Transpile-Aufgabe, die mit "Npm ausführen Transpile." Dies generiert eine Datei "App.js", die in Node.js ausgeführt werden kann, da die JSX mit JavaScript ersetzt wurde.

Da ich reagieren als die Ansichtsebene verwende, übergibt die Todos vom Controller in der List-Komponente und den HTML-Code zurückgegeben werden soll. In Node.js der Code in "App.js" ist privat und kann nur öffentlich gemacht werden explizit exportieren. Ich werde eine Funktion exportieren, GetList aus app.jsx damit die List-Komponente, die extern erstellt werden kann Denken Sie daran, die Transpile-Aufgabe ausgeführt, sodass app.js aktualisiert wird:

function getList(todos) {
  return <List todos={todos} />;
}
exports.getList = getList;

HomeController ist in c# und die GetList-Funktion ist in JavaScript. Um über diese Grenze aufzurufen, verwende ich Edge.js (tjanczuk.github.io/edge), der durch Ausführen von Install-Package Edge.js über NuGet verfügbar ist. Edge.js erwartet, dass Sie eine c#-Zeichenfolge, die mit Node.js-Code, der eine Funktion mit zwei Parametern zurück übergeben. Der erste Parameter enthält die Daten, die von c# übergeben, und der zweite Parameter ist ein Rückruf verwendet, um die JavaScript-Daten an die C#-zurückzugeben. Nach der Ausführung "Npm Install reagieren-Dom" reagieren des Server-Rendering-Funktion einbringen, verwende ich Edge.js zum Erstellen einer Funktion, die HTML für die List-Komponente aus dem übergebenen Todos-Array zurückgibt:

private static Func<object, Task<object>> render = Edge.Func(@"
  var app = require('../../Scripts/app.js');
  var ReactDOMServer = require('react-dom/server');
  return function (todos, callback) {
    var list = app.getList(todos);
    callback(null, ReactDOMServer.renderToString(list));
  }
");

Aus der Node.js-Code erstellt Edge.js eine C#-Funktion, die ich in einer Variablen namens "render" im HomeController zuweisen. Rendern von Aufrufen mit einer Liste von Todos gibt den HTML-Code zurück. Ich füge diesen Aufruf an die Index-Methode, das Async/await-Muster verwenden, da Aufrufe Edge.js asynchron sind:

public async Task<ActionResult> Index()
{
  var todos = new TodoRepository().Todos.ToList();
  ViewBag.List = (string) await render(todos);
  return View();
}

Hinzugefügte den HTML-Code an die dynamische ViewBag-Klasse zurückgegeben wird, sodass ich es aus der Razor-Ansicht zugreifen kann. Obwohl reagieren alle Aufgaben durchführt, möchte ich noch eine Codezeile Razor zum Senden von HTML-Code an den Browser, und führen Sie das Server-Rendering:

<div id="content">@Html.Raw(ViewBag.List)</div>

Diese neue Ansatz für die progressive Verbesserung mag wie mehr Arbeit im Vergleich zu der alte Ansatz. Aber vergessen Sie nicht, mit diesem neuen Ansatz, der Code zum Rendern der Server den Client-Rendering-Code werden soll. Es wird nicht der duplizierte Aufwand durch die alte Vorgehensweise beim Aktivieren der Anwendung Server dargestellt in einer SPA vorhanden sein.

Filter auf dem Server

Die Todos muss gefiltert werden, damit entweder aktiven oder abgeschlossen derjenigen, die angezeigt werden können. Filtern bedeutet und Hyperlinks routing bedeuten. Ich habe nur reagieren, einem JavaScript-Renderer Razor ersetzt, die für Client und Server verwendet werden kann. Als Nächstes werde ich die gleiche Behandlung für routing gelten. Stattdessen verwenden Sie die Routinglösung, die ausgeliefert wird, mit ASP.NET MVC, werde ich mit dem Router der Navigation ersetzen (grahammendick.github.io/navigation), ein JavaScript-Router, der für Client und Server verwendet werden kann.

Ich führe "Npm Install Navigation", in dem Router zu bringen. Sie können sich vorstellen der Navigation Router wie einem Statusmechanismus, wobei jeder Zustand eine andere Ansicht innerhalb der Anwendung darstellt. In app.jsx konfiguriere ich den Router mit dem Status, der die Todo "Liste" Ansicht darstellt. Ich werde weisen, eine Route mit einem optionalen "Filter"-Parameter, damit die Filterung URLs dargestellt, wie "/ aktiv" und "/ abgeschlossen":

var Navigation = require('navigation');
var config = [
  { key: 'todoMVC', initial: 'list', states: [
    { key: 'list', route: '{filter?}' }]
  }
];
Navigation.StateInfoConfig.build(config);

Mit der alte Ansatz PE würden Sie die Filterlogik in den Controller ablegen. Mit dem neuen Ansatz befindet sich die Filterlogik innerhalb des Codes reagieren, damit es auf dem Client wiederverwendet werden kann, wenn ich in einer SPA umzuwandeln. Die List-Komponente in den Filter übernimmt und vergleichen Sie ihn mit einem Todo Status "abgeschlossen" zum Bestimmen der Listenelemente anzeigen:

var filter = this.props.filter;
var todoFilter = function(todo){
  return !filter || (filter === 'active' && !todo.Completed)
    || (filter === 'completed' && todo.Completed);
}
var todos = this.props.todos.filter(todoFilter).map(function(todo) {
  return <li key={todo.Id}>{todo.Title}</li>;
});

Ich ändere den HTML-Code zurückgegeben, aus der List-Komponente der Filter Hyperlinks unterhalb der gefilterten Todo-Liste enthalten:

<div>
  <ul>{todos}</ul>
  <ul>
    <li><a href="/">All</a></li>
    <li><a href="/active">Active</a></li>
    <li><a href="/completed">Completed</a></li>
  </ul>
</div>

Die exportierte "GetList"-Funktion benötigt einen zusätzlichen Parameter, damit er die neue Filter-Eigenschaft in der List-Komponente übergeben kann. Dies ist die letzte Änderung app.jsx um Unterstützung für das Filtern, ist ein guter Zeitpunkt erneut ausführen, die Gulp Transpile-Aufgabe, um eine neue app.js generieren.

function getList(todos, filter) {
  return <List todos={todos} filter={filter} />;
}

Der ausgewählte Filter muss aus der URL extrahiert werden. Sie könnten versucht sein, eine ASP.NET MVC-Route zu registrieren, sodass der Filter an den Controller übergeben wird. Jedoch ist dies die Route, die bereits in der Navigation Router konfiguriert duplizieren. Den Navigationsbereich Router verwende ich stattdessen um den Filter-Parameter zu extrahieren. Zunächst entferne ich alle Erwähnung von Routenparameter aus der C#-RouteConfig-Klasse.

routes.MapRoute(
  name: "Default",
   url: "{*url}",
  defaults: new { controller = "Home", action = "Index" }
);

Der Navigationsbereich-Router verfügt über eine NavigateLink-Funktion zum Analysieren von URLs. Sie übergeben eine URL, und speichert die extrahierten Daten in einem StateContext-Objekt. Sie können dann diese Daten mit den Namen der Route-Parameters als Schlüssel zugreifen:

Navigation.StateController.navigateLink('/completed');
var filter = Navigation.StateContext.data.filter;

Angeschlossen dieser Route Parameter extrahieren Code wird in dem Rendern Edge.js funktionieren, damit der Filter aus der aktuellen URL abgerufen werden kann, und die GetList-Funktion übergeben wird. Aber JavaScript auf dem Server kann nicht auf die URL der aktuellen Anforderung zugreifen, damit er vom C#-, zusammen mit den Todos, über den ersten Parameter der Funktion übergeben werden muss:

return function (data, callback) {
  Navigation.StateController.navigateLink(data.Url);
  var filter = Navigation.StateContext.data.filter;
  var list = app.getList(data.Todos, filter);
  callback(null, ReactDOMServer.renderToString(list));
}

Die entsprechende Änderung der Index-Methode des HomeController ist ein Objekt in den Renderingaufruf übergeben, die sowohl die URL aus der serverseitigen-Anforderung und der Aufgabenliste enthält.

var data = new {
  Url = Request.Url.PathAndQuery,
  Todos = todos
};
ViewBag.List = (string) await render(data);

Mit dem Filter vorhanden, ist die serverseitige-Phase des Builds abgeschlossen. Server-Rendering-Garantie ab, ist der Aufgabenliste können von allen Browsern und Suchmaschinen angezeigt. Es ist geplant, die Erfahrung für moderne Browser zu verbessern, indem Sie das Filtern der TODO-Liste auf dem Client. Der Navigationsbereich Router den Browserverlauf verwalten und sicherstellen, dass ein Client gefilterte Aufgabenliste lesezeichenfähig bleibt.

Wiedergabe auf dem Client

Wenn ich die Benutzeroberfläche mit Razor entwickelt hatte, würde ich nicht näher jetzt die Zeile als wenn dargelegten beenden SPA. Zum Replizieren der Renderinglogik in JavaScript ist Grund nenne PE nicht mehr so ging. Aber mit dem reagieren, ist es ganz im Gegenteil, da alle app.js Code auf dem Client wiederverwendet werden kann. Wie ich reagieren verwendet, um die List-Komponente auf dem Server in HTML zu rendern, wird es verwendet dieselbe Komponente auf dem DOM auf dem Client gerendert werden soll.

Um die List-Komponente auf dem Client Rendern benötige ich den Zugriff auf die Todos. Ich werde die Todos verfügbar machen, indem Sie in eine JavaScript-Variable als Teil des Renderns Server senden. Die ViewBag-Klasse in der HomeController TODO-Liste hinzufügen, kann ich sie innerhalb der Razor-Ansicht ein JavaScript-Array serialisiert:

<script>
  var todos = 
    @Html.Raw(new JavaScriptSerializer().Serialize(ViewBag.Todos));
</script>

Ich erstelle eine client.js-Datei im Ordner Skripts zum Client Renderinglogik zu speichern. Dieser Code wird genauso wie die Node.js-Code aus, ich Edge.js, behandeln das Server-Rendering übergeben, sondern optimiert, um auf die Unterschiede in der Umgebung berücksichtigen. Also die URL stammen Location-Objekt des Browsers, anstatt die serverseitige-Anforderung, und reagieren rendert die List-Komponente in das Content-div-Tag, und nicht in eine HTML-Zeichenfolge:

var app = require('./app.js');
var ReactDOM = require('react-dom');
var Navigation = require('navigation');
Navigation.StateController.navigateLink(location.pathname);
var filter = Navigation.StateContext.data.filter;
var list = app.getList(todos, filter);
ReactDOM.render(list, document.getElementById('content'));

Ich werde app.jsx eine Linie hinzugefügt, die die Navigation Router teilt mit, dass ich verwende HTML5-Verlauf anstatt der Hash-Verlauf-Standardeinstellung. Wenn ich dies nicht gemacht hätte, würde die NavigateLink-Funktion denken, dass die URL geändert hat und den Browser Hash entsprechend aktualisieren:

Navigation.settings.historyManager = 
  new Navigation.HTML5HistoryManager();

Wenn ich einen Skriptverweis client.js direkt mit der Razor-Ansicht, die am Ende die Änderungen für Client Rendern erforderlich wäre hinzufügen können. Leider ist es nicht so einfach, da der erfordern-Anweisungen in client.js sind Teil der Node.js-Modul geladen und vom Browser nicht erkannt. Ich verwende ein plug-in schlucken aufgerufen browserify zum Erstellen einer Aufgabe, Pakete client.js und alle ihre erforderlichen Module in einer JavaScript-Datei, die ich dann die Razor-Ansicht hinzufügen können. Ich führe "Npm Install browserify Vinyl Quelldatenstrom" im plug-in bringen:

var browserify = require('browserify');
var source = require('vinyl-source-stream');
gulp.task('bundle', ['transpile'], function(){
  return browserify('Scripts/client.js')
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('Scripts/'))
});

Ich möchte nicht die Bundle-Aufgabe ausgeführt, sofern sie die letzten Änderungen an app.jsx enthält. Um sicherzustellen, dass der Transpile-Vorgang immer zuerst ausgeführt wird, wurde ich eine Abhängigkeit des Tasks "Paket". Sie können sehen, dass der zweite Parameter eines Vorgangs schlucken abhängigen Elemente aufgeführt sind. Ich werde einen Eintrag im Abschnitt Skripts package.json für den Task Paket hinzufügen. Mit dem Befehl "Npm ausführen Bündel" bundle.js erstellen, und ich füge einen Skriptverweis an das Ende der Razor-Ansicht auf:

<script src="~/Scripts/bundle.js"></script>

Server-Rendering der HTML-Code habe ich eine Anwendung, die schneller als startet, erstellt todomvc.com da sie alle Inhalte anzeigen können, bis deren JavaScript lädt und ausführt. Auf ähnliche Weise, wenn der JavaScript-Code in meiner Anwendung geladen ist, ein Client Rendern ausgeführt wird. Im Gegensatz dazu DOM überhaupt nicht aktualisiert. Dies ermöglicht das Reagieren auf den Server-gerenderten Inhalt anfügen, damit nachfolgende TODO-Liste filtern auf dem Client verarbeitet werden kann.

Filtern auf dem Client

Wenn Sie PE die herkömmliche Weise durchführen, können Sie auf dem Client durch Umschalten Klassennamen zum Steuern der Sichtbarkeit der TODO-Elemente filtern implementieren. Aber ohne eine JavaScript-Router zu helfen, sehr leicht Browserverlauf zu unterbrechen. Wenn Sie nicht zum Aktualisieren der URL angegeben, werden nicht die gefilterte Liste lesezeichenfähig. PE moderne wie Weise ich habe bereits den Navigation Router ausgeführt auf dem Client, den Browserverlauf intakt zu halten.

Um die URL aktualisieren, wenn ein Filter Link geklickt wird, muss das Click-Ereignis abfangen und den Hyperlink-Referenz an den Router NavigateLink-Funktion übergeben. Es erfolgt eine reagieren-Plug-In für die Navigation-Router, der dies für mich behandelt erstelle ich die Hyperlinks in der vorgeschriebenen Weise. Beispielsweise anstelle des Schreibens von < ein Href = "/ aktiv" > aktiven </a >, das plug-in bietet, RefreshLink reagieren Komponente verwenden muss:

var RefreshLink = require('navigation-react').RefreshLink;
<RefreshLink toData={{filter: 'active'}}>Active</RefreshLink>

Nach der Ausführung "Npm Install Navigation reagieren", in das plug-in zu bringen, aktualisiere ich die List-Komponente in app.jsx durch die drei Filter links den entsprechenden RefreshLink ersetzen.

Um die Benutzeroberfläche und die URL zu synchronisieren, muss die TODO-Liste zu filtern, bei jeder Änderung die URL – nicht nur wenn ein Filter Hyperlink sondern auch geklickt wird, wenn die Browser-zurück-Taste gedrückt wird. Anstatt separate Ereignislistener kann hinzugefügt werden, dass geschieht ein einzigen Listener mit dem Navigationsbereich-Router, der eine Navigation Zeitpunkt aufgerufen wird. In den Zustand "List" als Teil der Konfiguration des Routers erstellten, muss Navigation Listener angefügt werden. Zunächst wird der Navigation Router mit den Schlüsseln aus der Konfiguration dieser Zustand zugreifen:

var todoMVC = Navigation.StateInfoConfig.dialogs.todoMVC;
var listState = todoMVC.states.list;

Ein Listener Navigation ist eine Funktion, die den Status "Navigation"-Eigenschaft zugewiesen. Bei jeder Änderung die URL wird der Navigation Router rufen Sie diese Funktion und die Daten aus der URL extrahierten übergeben. Ich ersetze den Code in client.js mit einem Listener Navigation, das die List-Komponente in das "Inhalt" div-Tag mit dem neuen Filter erneut gerendert wird. Reagieren übernimmt den Rest, aktualisieren das DOM zum Anzeigen der soeben gefilterte Todos:

listState.navigated = function(data){
  var list = app.getList(todos, data.filter);
  ReactDOM.render(list, document.getElementById('content'));
}

Implementieren Sie die Filterung, entfernt ich versehentlich im Code aus client.js, die dem ersten Client Rendern ausgelöst. Ich werde diese Funktionalität wiederherstellen, indem Sie einen Aufruf von "Navigation.start" am unteren Rand client.js hinzufügen. Dies wird effektiv die aktuellen Browser-URL in der Router NavigateLink-Funktion, die Navigation Listener ausgelöst und führt der Client Rendern übergeben. Ich werde die Bundle-Aufgabe, um die aktuellen Änderungen in app.js und bundle.js bringen erneut ausführen.

Der neue Ansatz zur PE ist modernen Alchemy. Es stellt die Basis-Metall einer Anwendung Server gerendert, in der SPA Gold. Führt eine besondere Art von Base Metall für die Transformation funktioniert, aber eine, die aus JavaScript-Bibliotheken erstellt wird, die ausgeführt wird ebenso auf dem Server und im Browser: Reagieren und die Navigation Router anstelle Razor und ASP.NET MVC-routing. Dies ist der neue Chemie für das Web.

Ausschneiden Senf

Das Ziel von PE ist eine Anwendung, die in allen Browsern funktioniert und bietet eine verbesserte Erfahrung für moderne Browser. Aber bei der Erstellung dieses verbesserte Erfahrung, habe ich der Aufgabenliste in älteren Browsern funktionieren beendet. Die SPA-Konvertierung verwendet die HTML5-Verlaufs-API, die Internet Explorer 9, z. B. unterstützt.

PE nicht über die gleiche wie für alle Browser. Die TODO-Liste keiner SPA in Internet Explorer 9 enthalten. In Browsern, die HTML5-Verlauf nicht unterstützen, kann ich auf die Server-gerenderten Anwendung zurückgreifen. Ich ändere die Razor-Ansicht, um bundle.js, dynamisch zu laden, damit sie nur für Browser gesendet wird, die HTML5-Verlauf zu unterstützen:

if (window.history && window.history.pushState) {
  var script = document.createElement('script');
  script.src = "/Scripts/bundle.js";
  document.body.appendChild(script);
}

Diese Überprüfung wird "Ausschneiden Senf" bezeichnet, da es sich bei nur jene Browser, die die Mindestanforderungen der Empfang der JavaScript-Code betrachtet werden. Das Endergebnis entspricht dem Web den optischen Eindruck, kann das gleiche Bild entweder ein Kaninchen oder eine Ente aussehen. Sehen Sie sich die TODO-Liste über einen modernen Browser und eine SPA ist, aber er Squint verwenden einen alten Browser, und es ist eine traditionellen Client / Server-Anwendung.


Graham Mendickglaubt in einem Web für alle zugänglich und freut sich durch die neuen Möglichkeiten für progressive Verbesserung, die isomorph JavaScript geöffnet hat. Er ist Autor von der Navigation JavaScript-Router kann er hofft Personen isomorph wechseln können. Erhalten Sie ihn auf Twitter: @grahammendick.

Vielen Dank an den folgenden technischen Experten von Microsoft für die Überprüfung dieses Artikels: Steve Sanderson
Steve Sanderson ist ein Web-Entwickler das ASP.NET Team bei Microsoft. Seine aktuellen Schwerpunkt liegt auf ASP.NET für Entwickler Erstellen von umfangreichen JavaScript hervorragende vornehmen.