First, the preface
In the previous topic quickly introduced KNOCKOUTJS related knowledge points, but also wrote a few simple examples, hope that through these examples you can quickly get started Knockoutjs. To give you a clear view of Knockoutjs's application in real-world projects, this topic will show you how to use webapi+bootstrap+knockoutjs+asp.net MVC to create a single page Web program. This pattern is now used in most companies ' actual projects.
Second, SPA (single page) benefits
before introducing the specific implementation, I think it is necessary to introduce the spa in detail. SPA, abbreviated as the single page Web application, is a Web application that loads individual HTML pages and dynamically updates the page when users interact with the application. The browser initially loads the necessary HTML, CSS, and JavaScript, all of which are done on this page, and are controlled by JavaScript.
The advantage of a single page program is that:
A better user experience that allows users to feel the speed and fluency of native apps in the Web App.
Separation of the front and rear concerns, the front-end is responsible for the interface display, the back-end is responsible for data storage and calculation, their respective roles, will not be the logic of the front and back end mixed together.
Reduce server pressure, the server can only generate data, without the need to display logic and page logic, increase server throughput. The front-end of Razor syntax writing in MVC requires the server to complete the synthesis and output of the page.
The same set of back-end programs can be used directly for web interface, mobile phone, tablet and many other clients.
Of course, the single page program, in addition to the advantages listed above, also has its shortcomings:
Not conducive to SEO. It doesn't matter if it's a management system.
The initial loading time is relatively increased. Because all JS, CSS resources will be completed in the first load, so that the back of the page smooth. For this, you can use bundle in asp.net mvc for file binding. Detailed use of bundle reference articles: Http://www.jb51.net/article/84329.htm, http://www.jb51.net/article/84329.htm and http:// Www.jb51.net/article/82174.htm.
Navigation is not available. If you have to navigate, you need to move forward and back. For this, you can realize the forward and backward function to make up for it. In fact, now the mobile phone Web page is so dry, and now also to the above navigation. For some enterprise backend management system, also can do so.
High level of skill and development cost to developers. For this, it is not a matter, programmers need to continue to learn to recharge, fortunately some of the front-end framework is very good to start.
third, the use of ASP.net mvc+webapi+bootstrap+knockoutjs to achieve spa
The advantages and disadvantages of the spa are described in detail, and then let's use asp.net Mvc+webapi+bs+ko to implement a single page program that will experience the smooth and contrasting effects of the original ASP.net MVC +razor pages.
1. Create asp.net Web application engineering using VS2013, and check MVC and Webapi class libraries. See the following figure in detail:
2. Create the corresponding warehousing and model. A simple task management system is shown here. The specific model and warehousing code are as follows:
Task Entity class implementation:
Public enum taskstate
{
Active = 1,
Completed =2
}
///<summary>
///task entity
///</ Summary> public
class Task
{public
int Id {get; set;}
public string Name {get; set;}
public string Description {get; set;}
Public DateTime CreationTime {get; set;}
Public DateTime finishtime {get; set;}
public string Owner {get; set;}
Public Taskstate State {get; set;}
Public Task ()
{
creationtime = DateTime.Parse (DateTime.Now.ToLongDateString ());
state = taskstate.active;
}
}
Task Warehousing class implementation:
<summary>///here Warehousing Direct use of sample data as a demo, real projects need to dynamically load from the database///</summary> public class Taskrepository {#region Static Filed private static lazy<taskrepository> _taskrepository = new Lazy<taskrepository> (() => new Tas
Krepository ());
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, smooth experience", Owner = "Learning hard", Fini Shtime = DateTime.Parse (DateTime.Now.AddDays (1). ToString (CultureInfo.InvariantCulture))}, new Task {Id =2, Name = "Learning Knockoutjs", Description = "Knockoutjs is a MVVM Class library, supports bidirectional binding ", Owner =" Tommy Li ", Finishtime = DateTime.Parse (DateTime.Now.AddDays (2). ToString (CultureInfo.InvariantCulture))}, new Task {Id =3, Name = "Learning Angularjs", Description = "Angularjs is MVVM framework, set MVVM and MVC are integrated with. ", Owner =" Li Zhi ", FinisHtime = DateTime.Parse (DateTime.Now.AddDays (3). ToString (CultureInfo.InvariantCulture))}, new Task {Id =4, Name = "Learning asp.net mvc Web site", Description = "Glimpse is a. NET Performance testing tools, support asp.net, asp.net mvc, EF, and so on, the advantage is that no need to modify the original project any code, and can output code to perform the execution of all aspects of the time ", Owner =" Tonny Li ", Finishtime = DATETIME.PA RSE (DateTime.Now.AddDays (4).
ToString (CultureInfo.InvariantCulture))},};
#endregion #region Public Methods public ienumerable<task> GetAll () {return _tasks; Public Task get (int id) {return _tasks.
Find (p => p.id = = Id);
Public task Add {if (item = null) {throw new ArgumentNullException ("item"); } item. Id = _tasks.
Count + 1; _tasks.
ADD (item);
return item; public void Remove (int id) {_tasks.
RemoveAll (p => p.id = Id);
public bool Update (Task Item) {if (item = null) {throw new ArgumentNullException ("item"); var TaskItem = Get (item.
ID);
if (TaskItem = = null) {return false; } _tasks.
Remove (TaskItem); _tasks. ADD (item);
return true;
} #endregion}
3. Add bootstrap and Knockoutjs libraries through NuGet.
4. Implement back-end data services. Here back-end services are implemented using ASP.net webapi. The specific implementation code is as follows:
<summary>///Task Webapi, providing data Services///</summary> public class Taskscontroller:apicontroller {Priv
Ate readonly taskrepository _taskrepository = taskrepository.current; Public ienumerable<task> GetAll () {return _taskrepository.getall ().
(a => a.id);
Public Task get (int id) {var item = _taskrepository.get (ID);
if (item = = null) {throw new httpresponseexception (Httpstatuscode.notfound);
return item; [Route ("Api/tasks/getbystate")] public ienumerable<task> getbystate (string state) {ienumerable<task> R
Esults = new list<task> (); Switch (state.
ToLower ()) {case "": Case "all": results = _taskrepository.getall ();
Break Case "Active": results = _taskrepository.getall ().
Where (t => t.state = = taskstate.active);
Break Case "Completed": results = _taskrepository.getall ().
Where (t => t.state = = taskstate.completed);
Break } results = results.
(t => t.id);
return results;
}
[HttpPost] public task Create (task item) {return _taskrepository.add (item); [Httpput] public void put (Task item) {if (!_taskrepository.update (item)) {throw new Httpresponseexception (HttpS
Tatuscode.notfound);
} public void Delete (int id) {_taskrepository.remove (ID);
}
}
5. Use the ASP.net MVC bundle to package resources. The corresponding Bundleconfig implementation code is as follows:
<summary>///only need to supplement some of the missing CSS and JS files. Because some CSS and JS files have been added to create the template///</summary> public class Bundleconfig {//For more information on bundling, visit h ttp://go.microsoft.com/fwlink/? linkid=301862 public static void Registerbundles (Bundlecollection bundles) {bundles. ADD (New Scriptbundle ("~/bundles/jquery").
Include ("~/scripts/jquery-{version}.js")); Bundles. ADD (New Scriptbundle ("~/bundles/jqueryval").
Include ("~/scripts/jquery.validate*")); Use the development version of Modernizr to develop with and learn from.
Then, when you are ' RE//ready for production, use the build tool in http://modernizr.com to pick only the tests your need. Bundles. ADD (New Scriptbundle ("~/bundles/modernizr").
Include ("~/scripts/modernizr-*")); Bundles. ADD (New Scriptbundle ("~/bundles/bootstrap").
Include ("~/scripts/bootstrap.js", "~/scripts/bootstrap-datepicker.min.js")); Bundles. ADD (New Stylebundle ("~/content/css"). Include ("~/content/bootstrap.css", "~/content/bootstrAp-datepicker3.min.css "," ~/content/site.css ")); Bundles. ADD (New Scriptbundle ("~/bundles/knockout"). Include ("~/scripts/knockout-{version}.js", "~/scripts/knockout.validation.min.js", "~/scripts/
Knockout.mapping-latest.js ")); Bundles. ADD (New Scriptbundle ("~/bundles/app").
Include ("~/scripts/app/app.js"));
}
}
6. Because we need to make the enumeration type appear as a string on the page. The enumeration is converted to numeric types when the default is serialized. So make the following changes to the Webapiconfig class:
public static class Webapiconfig
{public
static void Register (httpconfiguration config)
{
//Web API Configuration and Services
//Web API routing
config. Maphttpattributeroutes ();
Config. Routes.maphttproute (
name: "Defaultapi",
routetemplate: "Api/{controller}/{id}",
defaults:new {id = Routeparameter.optional}
);
Enables serialization to serialize property config using the camel-case style
. Formatters.JsonFormatter.SerializerSettings.ContractResolver = new Camelcasepropertynamescontractresolver ();
Serializes a string config when the enumeration type is serialized
. FORMATTERS.JSONFORMATTER.SERIALIZERSETTINGS.CONVERTERS.ADD (New Stringenumconverter ());
}
Note: If you do not use the Hump lowercase style serialization above, adjust the page when the data is bound. If you use name capitalization directly when you bind the Name property, this property is not defined incorrectly if you use the name method. Since JS is named for variables using the Hump lowercase style. So it is recommended that you use the Hump lowercase style for serialization, when binding can only be binding using the form "name". This is also more in line with the JS code specifications.
7. Modify the corresponding layout file and index file contents.
The
Layout file specific code is as follows:
8. Create the corresponding front-end scripting logic. Use the JS code to request the data, and create the corresponding ViewModel object for front-end binding. The specific JS implementation code is as follows:
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);
This.description (data.description);
This.finishtime (Data.finishtime);
This.owner (Data.owner);
This.state (data.state);
};
};
function Getalltasks () {sendajaxrequest ("get", function (data) {taskListViewModel.tasks.removeAll ();
for (var i = 0; i < data.length i++) {TaskListViewModel.tasks.push (data[i));
}, ' Getbystate ', {' state ': ' All '};
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}); } function Remove (item) {sEndajaxrequest ("DELETE", function () {getalltasks ();
}, Item.id);
The var task = new Taskmodel ();
function Handlecreateorupdate (item) {TASK.FROMJS (item);
Initdatepicker ();
Tasklistviewmodel.cancreate (FALSE);
$ (' #create '). CSS (' visibility ', ' visible ');
The function Handlebackclick () {tasklistviewmodel.cancreate (true);
$ (' #create '). CSS (' visibility ', ' hidden '); function Handlesaveclick (item) {if (item.id = = undefined) {sendajaxrequest ("POST", function (newitem) {//newitem is returned
Back to the object.
TaskListViewModel.tasks.push (NewItem); }, NULL, {name:item.name, description:item.description, FinishTime:item.finishTime, Owner:item.owner, State:ite
M.state});
else {sendajaxrequest ("put", function () {getalltasks (); }, NULL, {id:item.id, name:item.name, Description:item.description, FinishTime:item.finishTime, Owner:item.owner
, state:item.state});
} tasklistviewmodel.cancreate (True);
$ (' #create '). CSS (' visibility ', ' hidden '); } function Sendajaxrequest (HTTpmethod, callback, URL, reqdata) {$.ajax ("/api/tasks" + (URL?)
"/" + URL: ""), {type:httpmethod, Success:callback, data:reqdata});
var initdatepicker = function () {$ (' #create. DatePicker '). DatePicker ({autoclose:true});
$ ('. Nav '). On (' Click ', ' Li ', function () {$ ('. Nav li.active '). Removeclass (' active ');
$ (this). addclass (' active ');
});
$ (document). Ready (function () {getalltasks ();
Bind Ko.applybindings (Tasklistviewmodel, $ (' #list ') using Knockoutjs. Get (0));
Ko.applybindings (Task, $ (' #create '). Get (0));
});
By this, our single page program has been developed, and then we will run to see the effect.
Run the results from the above diagram can be seen, once the page is loaded, all operations are like in a page operation, completely feel the browser page in circles. Do you feel the smoothness of the spa compared to the previous pages developed using the ASP.net MVC +razor? Before using the page developed by ASP.net MVC +razor, you can just request a page and you will feel the whole page refresh, so the user experience is very bad.
Iv. comparing with razor development model
I believe you have seen the effect of the spa advantage, and then I think it is necessary to implement the traditional Web page with a comparison. With the razor development method mainly has the following 2 points different:
1. When the page is rendered, the data is processed at the browser end. Rather than on the server. Distribute the rendering pressure to the browser side of each user, reducing the pressure on the Web server. In exchange for the razor syntax, the front-end page binding statement should be as follows:
@Model ienumerable<knockoutjsspa.models.task>
@foreach (var item in Model)
{
<tr>
< Td> @item. Name</td>
<td> @item. description</td>
</tr>
}
These are rendered at the server driven by razor engine. This is also the reason why pages developed with Razor will see the page spin. Because every time you switch a page, you need to request the service side for rendering, the server renders the HTML back to the client to display.
2. The bound data is dynamic. means that changes in the data model will immediately be reflected on the page. This effect is attributed to the bidirectional binding mechanism implemented by KNOCKOUTJS.
In this way, for program development is also simple, the Web API is only responsible for providing data, and front-end pages also reduce a lot of DOM operations. Because DOM operations are cumbersome and error-prone. This also means reducing the hidden bugs in the program. And, a back-end service, can be used for mobile phones, web browsers and platforms to use multiple platforms, to avoid duplication of development.
V. Summary
Here, the introduction of this article is introduced. This article mainly introduces the use of Knockoutjs to complete a spa program. In fact, in the actual work, to create a single page of the program model more use ANGULARJS. Then there are a lot of Knockoutjs, but Knockoutjs is just a MVVM framework whose routing mechanism requires some other class libraries, as we use the routing mechanism in ASP.net mvc, and you can also use the Director.js front-end routing framework. ANGULARJS is a MVVM+MVC framework relative to Knockoutjs. So the next topic will introduce how to use Angularjs to create a single page program (SPA).
This article all source code downloads: Spawithknockoutjs
If you want to further study, you can click here to learn, and then attach 3 wonderful topics:
Bootstrap Learning Course
Bootstrap Practical Course
Bootstrap Plugin Usage Tutorial
The above is the entire content of this article, I hope to help you learn.