1. Vorwort
Im vorherigen Thema habe ich die Wissenspunkte im Zusammenhang mit KnockoutJs schnell vorgestellt und einige einfache Beispiele geschrieben. Ich hoffe, dass Sie anhand dieser Beispiele schnell mit Knockoutjs beginnen können. Um zu ermöglichen, dass alle die Anwendung von KnockoutJs in tatsächlichen Projekten klar sehen, wird dieses Thema vorgestellt, wie Sie WebAPI+Bootstrap+KnockoutJS+ASP.NET MVC verwenden, um ein einseitiges Webprogramm zu erstellen. Dieses Modell wird jetzt auch in den tatsächlichen Projekten der meisten Unternehmen verwendet.
2. Spa (Einzelseite) Vorteile
Vor der Einführung der spezifischen Implementierung bin ich der Meinung, dass es notwendig ist, Spa im Detail einzuführen. Spa, die Abkürzung einer einzelnen Webanwendung, ist eine Webanwendung, die eine einzelne HTML -Seite lädt und die Seite dynamisch aktualisiert, wenn der Benutzer mit der Anwendung interagiert. Der Browser lädt zu Beginn die erforderlichen HTML, CSS und JavaScript. Alle Vorgänge werden auf dieser Seite abgeschlossen und von JavaScript gesteuert.
Die Vorteile von einseitigen Programmen sind:
Eine bessere Benutzererfahrung ermöglicht es Benutzern, die Geschwindigkeit und Glätte native Apps in der Web -App zu erleben.
Trennen Sie die Vorder- und Rücksendeprobleme, das Frontend ist für die Schnittstellenanzeige verantwortlich und das hintere Ende ist für die Datenspeicherung und -Computerin verantwortlich, jeweils seine eigenen Aufgaben und mischt die Logik der Vorder- und Rückseite nicht zusammen.
Um den Druck auf den Server zu verringern, muss der Server nur Daten generieren, unabhängig von der Anzeigelogik und der Seitenlogik und erhöht den Serverdurchsatz. Das in der Razor-Syntax in MVC geschriebene Front-End-Abschluss erfordert, dass der Server die Synthese der Seite abschließt und diese dann ausgibt.
Dieselben Back-End-Programme können direkt für mehrere Clients wie Weboberflächen, Mobiltelefone, Tablets usw. verwendet werden.
Natürlich haben einseitige Programme zusätzlich zu den oben aufgeführten Vorteilen auch ihre Mängel:
SEO nicht förderlich. Wenn dies ein Managementsystem ist, wird es sich nicht auswirken.
Die anfängliche Belastungszeit ist relativ erhöht. Da alle JS- und CSS -Ressourcen zum ersten Mal geladen werden, wird die nachfolgende Seite reibungslos. Zu diesem Zweck können Sie Bündel in ASP.NET MVC verwenden, um Dateien zu binden. Eine detaillierte Verwendung von Bundle finden Sie unter Artikel: http://www.vevb.com/article/84329.htm, http://www.vevb.com/article/84329.htm und http://www.vevb.com/article/82174.htm.
Die Navigation ist nicht verfügbar. Wenn Sie navigieren müssen, müssen Sie sich selbst vorantreiben und sich zurückziehen. Dafür können Sie die Vorwärts- und Rückfunktionen selbst erkennen, um dies auszugleichen. Tatsächlich tun dies die mobilen Webseiten jetzt und müssen jetzt noch die Navigation oben sein. Dies kann auch für einige Unternehmens -Backend -Management -Systeme erfolgen.
Hohe Entwicklungskosten für Entwickler. Dies ist kein Problem. Programmierer müssen immer wieder lernen, zu berechnen. Glücklicherweise sind einige Front-End-Frameworks sehr einfach zu bedienen.
3. Verwenden
Die Vor- und Nachteile des Spa wurden früher ausführlich eingeführt. Lassen Sie uns als nächstes ASP.NET MVC+WebAPI+BS+KO zur Implementierung eines einseitigen Programms verwenden, um die Glätte von SPA zu erleben und die Auswirkungen der Seiten des ursprünglichen ASP.NET MVC+Razor zu vergleichen.
1. Verwenden Sie VS2013, um ein ASP.NET -Webantragsprojekt zu erstellen, und überprüfen Sie die MVC- und WebAPI -Bibliothek. Weitere Informationen finden Sie in der Abbildung unten:
2. Erstellen Sie entsprechende Lagerhäuser und Modelle. Hier ist ein einfaches Task -Management -System. Der spezifische Modell und der Lagercode sind wie folgt:
Implementierung der Taskentity -Klasse:
public enum taskState {active = 1, ferast = 2} /// <summary> /// Aufgabenentität //// </summary> public class Task {public int id {get; Satz; } public String Name {get; Satz; } öffentliche Zeichenfolge Beschreibung {get; Satz; } public datetime creationtime {get; Satz; } public dateTime enden -Zeit {get; Satz; } public String -Besitzer {get; Satz; } public TaskState State {get; Satz; } public task () {creationTime = datetime.parse (datetime.now.tolongDatestring ()); State = taskState.active; }}Task Warehousing -Klassen -Implementierung:
/// <summary> /// Hier verwendet das Lagerhaus Beispieldaten als Demonstration. Das reale Projekt muss dynamisch aus der Datenbank geladen werden /// </summary> public class taskrepository {#region static eingereichtes privates statisches Lazy <TaskRepository> _taskrepository = new Lazy <Taskrepository> () => new TaskRepository ()); public static taskrepository current {get {return _taskrepository.Value; } } #endregion #region Fields private readonly List<Task> _tasks = new List<Task>() { new Task { Id =1, Name = "Create a SPA program", Description = "SPA(single page web application), The advantage of SPA is a small amount of bandwidth and a smooth experience", Owner = "Learning hard", FinishTime = DateTime.Parse(DateTime.Now.AddDays(1).ToString(CultureInfo.InvariantCulture)) }, new Task { Id =2, Name = "Learning KnockoutJs", Description = "KnockoutJs is an MVVM class library that supports two-way binding", Owner = "Tommy Li", FinishTime = Datetime.parse (datetime.now.adddays (2) .toString (CultureInfo.invariantCulture))}, neue Aufgabe {id = 3, name = "Learn AngularJs", Beschreibung = "Angularjs ist ein MVVM -Framework, das MVVM und MVC integriert. Datetime.parse (datetime.now.adddays (3) .toString (CultureInfo.invariantCulture)}, neue Task {id = 4, name = "Lernen Sie ASP.NET MVC -Website", Beschreibung Projekt und kann die Ausführungszeit jedes Links der Codeausführung ausgeben. #endregion #region public Methodien public iEnumerable <Task> getAll () {return _tasks; } öffentliche Aufgabe get (int id) {return _tasks.find (p => p.id == id); } public Task add (Task -Element) {if (item == null) {neue argumentNulLexception ("item"); } item.id = _tasks.count + 1; _tasks.add (item); Gegenstand zurückgeben; } public void remove (int id) {_tasks.removeall (p => p.id == id); } public bool update (Aufgabeelement) {if (item == null) {neue argumentNulLexception ("item"); } var taskitem = get (item.id); if (taskitem == null) {return false; } _tasks.remove (TaskItem); _tasks.add (item); zurückkehren; } #endregion}3. Fügen Sie Bootstrap- und Knockoutjs -Bibliotheken über Nuget hinzu.
4. Implementieren Sie Back-End-Datendienste. Hier wird der Backend -Dienst mit ASP.NET WebAPI implementiert. Der spezifische Implementierungscode lautet wie folgt:
/// <summary> /// Task -Webapi, Datendienste /// </summary> öffentliche Klasse TasksController: apicontroller {private readonly taskrepository _taskrepository = taskrepository.current; public iEnumerable <Task> getAll () {return _taskrepository.getall (). OrderBy (a => a.id); } öffentliche Aufgabe get (int id) {var item = _taskrepository.get (id); if (item == null) {throw New httPresponsexception (httpstatuscode.notfound); } Rückgabeartikel; } [Route ("api/tasks/getbyState")] public iEnumerable <Task> getbyState (String -Status) {iEnumerable <Task> resultes = New List <Task> (); Switch (state.tolower ()) {case "": case "all": resultation = _taskrepository.getall (); brechen; Fall "aktiv": resultation = _taskrepository.getall (). WO (t => T.State == TaskState.active); brechen; Fall "abgeschlossen": resultation = _taskrepository.getall (). WO (t => T.State == TaskState.com pleted); brechen; } results = results.ordby (t => t.id); Rückgabeergebnisse; } [Httppost] public Task erstellen (Task -Element) {return _taskrepository.add (item); } [Httpput] public void put (Task -Element) {if (! _Taskrepository.update (item)) {throw New httPesponsexception (httpstatusCode.notfound); }} public void delete (int id) {_taskrepository.remove (id); }}5. Verwenden Sie das ASP.NET MVC -Bundle, um die Ressourcen zu verpacken. Der entsprechende BundleConfig -Implementierungscode lautet wie folgt:
/// <summary> /// Fügen Sie einfach einige fehlende CSS- und JS -Dateien hinzu. Da beim Erstellen der Vorlage einige CSS- und JS -Dateien hinzugefügt wurden /// </summary> BundleConfig {// Weitere Informationen zum Bündeln finden ScriptBundle ("~/bündel/jQuery"). Include ("~/scripts/jQuery- {Version} .js")); bündel.add (neuer Skriptbundle ("~/bündel/jQueryval"). Include ("~/scripts/jQuery.Validate*")); // Verwenden Sie die Entwicklungsversion von Modernizr, um sich mit zu entwickeln und zu lernen. Wenn Sie // dann zur Produktion bereit sind, verwenden Sie das Build -Tool unter http://modernizr.com, um nur die von Ihnen benötigten Tests auszuwählen. bündel.add (neuer Skriptbundle ("~/bündel/modernizr"). Include ("~/scripts/modernizr-*")); bundles.add (neuer Skriptbundle ("~/bündel/bootstrap"). Include ("~/scripts/bootstrap.js", "~/scripts/bootstrap-datepicker.min.js"))); bündel.add (neuer styleBundle ("~/content/csS"). Include ("~/content/bootstrap.css", "~/content/bootstrap-datepicker3.min.css", "~/content/site.css")); bundles.add (neuer Skriptbundle ("~/bündel/knockout"). Include ("~/scripts/Knockout- {Version} .js", "~/scripts/knockout.validation.min.js", "~/scripts/knockout.mapping-latest.js"); bündel.add (neuer Skriptbundle ("~/bündel/App"). Include ("~/scripts/app/app.js")); }}6. Weil wir den Enum -Typ als Zeichenfolge auf der Seite erscheinen lassen müssen. Die Aufzählung wird bei serialisiertem serialisiert in einen numerischen Typ konvertiert. Daher müssen wir die folgenden Änderungen an der WebaPiconfig -Klasse vornehmen:
public static class webapiconfig {public static void Register (HTTPConfiguration config) {// Web -API -Konfiguration und -Dienste // Web -API -Routing -Konfiguration.MAPHTTTPATTTRIBUTEROUTES (); config.routes.maphttproute (Name: "defaultApi", routetemplate: "api/{controller}/{id}", Standards: neu {id = RoutesParameter.Optional}); // Serialisierung Camel Fallstil Serialisierungseigenschaft konfigurieren. // serialisieren Sie die String config.formatters.jsonFormatter.SerializerSettings.converters.Add (new StringenumConverter ()); }}HINWEIS: Wenn die Serialisierung von Kamel -Kleinbuchstaben oben nicht verwendet wird, sollten Sie auch Anpassungen vornehmen, wenn Daten auf der Seite binden. Verwenden Sie beispielsweise beim Bindungsnamenattribut die Namenskapitalisierung direkt. Wenn Sie die Namensmethode verwenden, wird in diesem Attribut aufgefordert, dass kein Definitionsfehler vorliegt. Da JS den Kamel -Kleinbuchstaben verwendet, um Variablen zu benennen. Daher wird empfohlen, dass Sie den Kamel -Kleinbuchstaben für die Serialisierung verwenden. Zu diesem Zeitpunkt können Sie nur die Form des "Namens" zum Binden verwenden. Dies entspricht eher den JS -Codespezifikationen.
7. Ändern Sie den entsprechenden Inhalt der entsprechenden Layout -Datei und des Indexdatei.
Der spezifische Code der Layoutdatei lautet wie folgt:
<!DOCTYPE html><html><head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> Learninghard SPA Application</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr")</head> <body> <div> <div> <div> <p>Simple Task Management System</p> </div> <div> <ul> <li><a href="/">Home</a></li> </ul> </div> </div> </div> <div id="main"> @RenderBody() <hr /> <footer> <p>© @DateTime.Now.Year - Learninghard SPA Application</p> </footer> </div> @scripts.render ("~/bündel/jQuery") @scripts.render ("~/bündel/bootstrap") @scripts.render ("~/bundles/Knockout") @scripts.render ("~/bündel/knockout") @scripts.render ("~/bundles/applits/app"). @{Viewbag.title = "index"; Layout = "~/Views/Shared/_Layout.cshtml";}<div id="list" data-bind="if:canCreate"><h2>Tasks</h2><div> <table> <thead> <tr> <th>Number</th> <th>Name</th> <th>Description</th> <th>People in charge</th> <th>Creation time</th> <Th> Abschlusszeit </th> <Th> statu </th> <th> </th> </tr> </tbody data-bind = "foreach: tasks"> <tr> <td data-bind = "text: id"> </td> <td> <a data-bind = "text: name: klick: Handle: Handle-datenbindDate" data-binddata ". description"></td> <td data-bind="text: owner"></td> <td data-bind="text: creationTime"></td> <td data-bind="text: finishTime"></td> <td data-bind="text: state"></td> <td><a data-bind="click:remove" href = "javaScript: void (0)"> entfernen </a> </td> </tbody> </table> </div> <div> <a href = "javaScript: void (0)" data-bind = "klicken: function (data, event) {settaskList ('All')}"> All </a> | <a href = "javaScript: void (0)" data-Bind = "Klicken: Funktion (Daten, Ereignis) {settaskList ('active')}"> Active </a> | <a href="javascript:void(0)" data-bind="click: function(data, event){ setTaskList('completed') }"> Completed</a></div><div> <a href="javascript:void(0)" data-bind="click: handleCreateOrUpdate">Add task</a></div><div id="create" style="visibility: Hidden "> <h2> Aufgabe hinzufügen </h2> <br/> <div> <div> <label für =" taskname "> name*</label> <div> <input type =" text "data-bind =" Wert: Name "id =" taskname "name =" taskname "placeholder =" name " Data-Bind = "Wert: Beschreibung" rows = "3" id = "taskDesc" name = "taskDesc" placeholder = "Beschreibung"> </textArea> </div> </div> <div> <label für = "taskbesitzer"> Person verantwortlich. <div> <label for="taskFinish">Estimated completion time*</label> <div> <input id="taskFinish" data-bind="value: finishTime" name="taskFinish"> </div> </div> <div> <label for="taskOwner">Status*</label> <div> <select id="taskState" data-bind="value: state"> <option>Active</option> <option> abgeschlossen </option> </select> </div> </div> <div> <div> <Schaltfläche data-bind = "Klicken: HandleSaveClick"> speichern </button> <button data-bind = "Klicken: landebackClick"> zurück </button> </div> </div> </div> </div> </div> </div> </div>8. Erstellen Sie die entsprechende Front-End-Skriptlogik. Verwenden Sie den JS-Code, um Daten anzufordern und entsprechende ViewModel-Objekte für die Front-End-Bindung zu erstellen. Der spezifische JS -Implementierungscode lautet wie folgt:
var TaskListViewModel = {Tasks: Ko.observablearray (), Cancreate: Ko.Observable (true)}; var taskmodel = function () {this.id = 0; this.name = ko.Observable (); this.description = ko.Observable (); this.finishTime = ko.Observable (); this.Owner = ko.Observable (); this.state = ko.Observable (); this.fromjs = function (data) {this.id = data.id; this.name (data.name); diese. this.finishTime (Data.finishTime); this.cond (Data.CORDER); this.state (Data.State); };}; Funktion getAllTasks () {sendajaxRequest ("get", function (data) {TaskListViewModel.Tasks.removeall () für (var i = 0; i <data.Length; i ++) {TaskListViewModel.taks.push (Data [i]); });}function setTaskList(state) { sendAjaxRequest("GET", function(data) { taskListViewModel.tasks.removeAll(); for (var i = 0; i < data.length; i++) { taskListViewModel.tasks.push(data[i]); }},'GetByState',{ 'state': state });} Funktion entfernen (item) {sendajaxRequest ("delete", function () {getAllTasks ();}, itel.id);} var task = new TaskModel (); initdatepicker (); TaskListViewModel.cancreate (false); $ ('#create'). CSS ('Sichtbarkeit', 'sichtbar');} Funktion realbackClick () {TaskListViewModel.cancreate (true); $ ('#create'). Beschreibung: item.Description, FinishTime: item.finishTime, Eigentümer: item.unterner, Zustand: item.state}); } else {sendajaxRequest ("put", function () {getAllTasks ();}, null, {id: it it id, name: item.name, Beschreibung: item.description, FinishTime: item.finishTime, Eigentümer: item.besitzer, Zustand: item.state}); } TaskListViewModel.cancreate (true); $ ('#create'). });} var initdatepicker = function () {$ ('#create .datepicker'). DatePicker ({autoclose: true});}; $ ('. nav'). on ('click', 'li', function () {$ ('. navi.active'). removeclass ('active'); $ (this) .AddClass ('active');});Zu diesem Zeitpunkt wurde unser einseitiges Programm entwickelt. Als nächstes führen wir es aus, um seine Wirkung zu sehen.
Aus dem obigen laufenden Ergebnis -Demonstrationsdiagramm können wir feststellen, dass nach dem Laden der Seite alle Vorgänge auf einer Seite funktionieren, und es fühlt sich an, als würde die Browser -Seite umkreisen. Verglichen die Seiten, die zuvor mit ASP.NET MVC + Rasiermesser entwickelt wurden, spüren Sie die Glätte von Spa? Zuvor, auf der mit ASP.NET MVC + Rasiermesser entwickelten Seite, müssen Sie nur eine Seite anfordern und die Aktualisierung der gesamten Seite spüren, die die Benutzererfahrung sehr schlecht macht.
4. Vergleich mit dem Modell der Rasiermesserentwicklung
Ich glaube, jeder hat die Vorteile von Spa aus den Ergebnissen gesehen. Als nächstes denke ich, dass es notwendig ist, es mit der traditionellen Art der Implementierung von Webseiten zu vergleichen. Es gibt zwei Hauptunterschiede zwischen der Rasierer -Entwicklungsmethode:
1. Wenn die Seite gerendert wird, werden die Daten auf der Browserseite verarbeitet. Nicht auf dem Server. Ziehen Sie der Browser -Seite jedes Benutzers den Druck auf, wodurch der Druck auf dem Website -Server verringert wird. Wenn es sich um eine Razor-Syntax handelt, sollte die Front-End-Seite-Bindungsanweisung wie folgt sein:
@Model iEnumerable <Knockoutjsspa.models.task> @foreach (var item in Modell) {<tr> <td>@item.name </td> <td>@item.description </td> </tr>}Diese werden von der Rasiermotor -Engine auf der Serverseite gerendert. Dies ist auch der Grund, warum Seiten, die mit Rasiermesser entwickelt wurden, die Seiten kreisen. Denn jedes Mal, wenn Sie eine Seite wechseln, müssen Sie den Server zum Rendern anfordern und nach dem Server die HTML zur Anzeige an den Client zurückgeben.
2. Die gebundenen Daten sind dynamisch. Dies bedeutet, dass Änderungen im Datenmodell sofort auf der Seite reflektiert werden. Dieser Effekt wird auf den von KnockoutJs implementierten Zwei-Wege-Bindungsmechanismus zurückgeführt.
Die Verwendung dieser Methode ist auch für die Programmentwicklung einfach. Die Web-API ist nur für die Bereitstellung von Daten verantwortlich, und die Front-End-Seite reduziert auch viele DOM-Vorgänge. Weil DOM-Operationen kompliziert und fehleranfällig sind. Dies bedeutet auch, implizite Fehler im Programm zu reduzieren. Darüber hinaus kann ein Back-End-Dienst von Mobiltelefonen, Webbrowsern und mehreren Plattformen verwendet werden, um eine wiederholte Entwicklung zu vermeiden.
5. Zusammenfassung
Zu diesem Zeitpunkt wird die Einführung dieses Artikels eingeführt. In diesem Artikel wird hauptsächlich die Verwendung von KnockoutJs zur Abschließung eines SPA -Programms vorgestellt. In der Tat basiert das Modell der Erstellung von Einzel-Seiten-Programmen in der tatsächlichen Arbeit eher auf AngularJs. Dann gibt es viele KnockoutJs, aber Knockoutjs ist nur ein MVVM-Framework, und sein Routing-Mechanismus muss mit einigen anderen Klassenbibliotheken verwendet werden, wie der Routing-Mechanismus in ASP.NET MVC. Im Vergleich zu KnockoutJs ist AngularJS ein MVVM+MVC -Framework. Im nächsten Thema werden wir also vorstellen, wie Sie AngularJs verwenden, um ein einzelnes Seitenprogramm (SPA) zu erstellen.
Laden Sie alle Quellcodes in diesem Artikel herunter: spawithknockoutjs
Wenn Sie weiterhin ausführlich studieren möchten, können Sie hier klicken, um Ihnen zu studieren und 3 aufregende Themen anzuhängen:
Bootstrap -Lern -Tutorial
Bootstrap Practical Tutorial
Bootstrap-Plug-in-Nutzungs-Tutorial
Das Obige dreht sich alles um diesen Artikel, ich hoffe, es wird für das Lernen aller hilfreich sein.