WebApi+Bootstrap+KnockoutJs打造单页面程序
一、前言在前一个专题快速介绍了KnockoutJs相关知识点,也写了一些简单例子,希望通过这些例子大家可以快速入门KnockoutJs。为了让大家可以清楚地看到KnockoutJs在实际项目中的应用,本专题将介绍如何使用WebApi+Bootstrap+KnockoutJs+Asp.net MVC来打造一个单页面Web程序。这种模式也是现在大多数公司实际项目中用到的。 二、SPA(单页面)好处在介绍具体的实现之前,我觉得有必要详细介绍了SPA。SPA,即Single Page Web Application的缩写,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。浏览器一开始会加载必需的HTML、CSS和JavaScript,所有的操作都在这张页面上完成,都由JavaScript来控制。单页面程序的好处在于: 更好的用户体验,让用户在Web app感受native app的速度和流畅。 分离前后端关注点,前端负责界面显示,后端负责数据存储和计算,各司其职,不会把前后端的逻辑混杂在一起。 减轻服务器压力,服务器只用生成数据就可以,不用管展示逻辑和页面逻辑,增加服务器吞吐量。MVC中Razor语法写的前端是需要服务器完成页面的合成再输出的。 同一套后端程序,可以不用修改直接用于Web界面、手机、平板等多种客户端。 当然单页面程序除了上面列出的优点外,也有其不足: 不利于SEO。这点如果是做管理系统的话是没影响的 初次加载时间相对增加。因为所有的JS、CSS资源会在第一次加载完成,从而使得后面的页面流畅。对于这点可以使用Asp.net MVC中Bundle来进行文件绑定。关于Bundle的详细使用参考文章:、和。 导航不可用。如果一定要导航需自行实现前进、后退。对于这点,可以自行实现前进、后退功能来弥补。其实现在手机端网页就是这么干的,现在还要上面导航的。对于一些企业后台管理系统,也可以这么做。 对开发人员技能水平、开发成本高。对于这点,也不是事,程序员嘛就需要不断学习来充电,好在一些前端框架都非常好上手。 三、使用Asp.net MVC+WebAPI+Bootstrap+KnockoutJS实现SPA前面详细介绍了SPA的优缺点,接下来,就让我们使用Asp.net MVC+WebAPI+BS+KO来实现一个单页面程序,从而体验下SPA流畅和对原始Asp.net MVC +Razor做出来的页面进行效果对比。 1.使用VS2013创建Asp.net Web应用程序工程,勾选MVC和WebAPI类库。具体见下图: 2. 创建对应的仓储和模型。这里演示的是一个简单任务管理系统。具体的模型和仓储代码如下: 任务实体类实现: ///
/// 任务实体 /// public class Task { public int Id { get; set; } public string Name { get; set; } public DateTime CreationTime { get; set; } public DateTime FinishTime { get; set; } public string Owner { get; set; } public Task() 任务仓储类实现:
/// 这里仓储直接使用示例数据作为演示,真实项目中需要从数据库中动态加载
///
public class TaskRepository
{
#region Static Filed
private static Lazy
public static TaskRepository Current endregionregion Fieldsprivate readonly List endregionregion Public Methodspublic IEnumerable public Task Get(int id) public Task Add(Task item) item.Id = _tasks.Count + 1; public void Remove(int id) public bool Update(Task item) var taskItem = Get(item.Id); _tasks.Remove(taskItem); endregion} 3. 通过Nuget添加Bootstrap和KnockoutJs库。 4. 实现后端数据服务。这里后端服务使用Asp.net WebAPI实现的。具体的实现代码如下:
/// Task WebAPI,提供数据服务
///
public class TasksController : ApiController
{
private readonly TaskRepository _taskRepository = TaskRepository.Current;
public IEnumerable public Task Get(int id) return item; [Route("api/tasks/GetByState")] results = results.OrderBy(t => t.Id); [HttpPost] [HttpPut] public void Delete(int id) 5. 使用Asp.net MVC Bundle对资源进行打包。对应的BundleConfig实现代码如下:
/// 只需要补充一些缺少的CSS和JS文件。因为创建模板的时候已经添加了一些CSS和JS文件
///
public class BundleConfig
{
// For more information on bundling,visit http://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( // Use the development version of Modernizr to develop with and learn from. Then,when you're bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( bundles.Add(new StyleBundle("~/Content/css").Include( bundles.Add(new ScriptBundle("~/bundles/knockout").Include( bundles.Add(new ScriptBundle("~/bundles/app").Include( 6. 因为我们需要在页面上使得枚举类型显示为字符串。默认序列化时会将枚举转换成数值类型。所以要对WebApiConfig类做如下改动: // Web API 路由
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( // 使得序列化使用驼峰式大小写风格序列化属性 注:如果上面没有使用驼峰小写风格序列化的话,在页面绑定数据的时候也要进行调整。如绑定的Name属性的时候直接使用Name大写,如果使用name方式会提示这个属性没有定义错误。由于JS是使用驼峰小写风格对变量命名的。所以建议大家加上使用驼峰小写风格进行序列化,此时绑定的时候只能使用"name"这样的形式进行绑定。这样也更符合JS代码的规范。 7. 修改对应的Layout文件和Index文件内容。 Layout文件具体代码如下:
Learninghard SPA Application
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
<div class="container body-content" id="main"> @Scripts.Render("~/bundles/jquery") <div id="list" data-bind="if:canCreate"> Tasks名称 |
描述 |
负责人 |
创建时间 |
完成时间 |
状态 |
| |
<div id="create" style="visibility: hidden">
添加任务
8. 创建对应的前端脚本逻辑。用JS代码来请求数据,并创建对应ViewModel对象来进行前端绑定。具体JS实现代码如下:
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]);
}},{ 'state': state });
}
function remove(item) {
sendAjaxRequest("DELETE",function () {
getAllTasks();
},item.id);
}
var task = new taskModel();
function handleCreateOrUpdate(item) {
task.fromJS(item);
initDatePicker();
taskListViewModel.canCreate(false);
$('#create').css('visibility','visible');
}
function handleBackClick() {
taskListViewModel.canCreate(true);
$('#create').css('visibility','hidden');
}
function handleSaveClick(item) {
if (item.id == undefined) {
sendAjaxRequest("POST",function (newItem) { //newitem是返回的对象。
taskListViewModel.tasks.push(newItem);
},null,{
name: item.name,description: item.description,finishTime: item.finishTime,owner: item.owner,state: item.state
});
} else {
sendAjaxRequest("PUT",{
id:item.id,name: item.name,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();
// 使用KnockoutJs进行绑定
ko.applyBindings(taskListViewModel,$('#list').get(0));
ko.applyBindings(task,$('#create').get(0));
});
到此,我们的单页面程序就开发完毕了,接下来我们来运行看看其效果。
从上面运行结果演示图可以看出,一旦页面加载完之后,所有的操作都好像在一个页面操作,完全感觉浏览器页面转圈的情况。对比于之前使用Asp.net MVC +Razor开发的页面,你是否感觉了SPA的流畅呢?之前使用Asp.net MVC +Razor开发的页面,你只要请求一个页面,你就可以感受整个页面刷新的情况,这样用户体验非常不好。
四、与Razor开发模式进行对比
相信大家从效果上已经看出SPA优势了,接下来我觉得还是有必要与传统实现Web页面方式进行一个对比。与Razor开发方式主要有以下2点不同:1.页面被渲染的时候,数据在浏览器端得到处理。而不是在服务器上。将渲染压力分配到各个用户的浏览器端,从而减少网站服务器的压力。换做是Razor语法,前端页面绑定语句应该就是如下:
这些都是在服务器端由Razor引擎渲染的。这也是使用Razor开发的页面会看到页面转圈的情况的原因。因为你每切换一个页面的时候,都需要请求服务端进行渲染,服务器渲染完成之后再将html返回给客户端进行显示。
2. 绑定的数据是动态的。意味着数据模型的改变会马上反应到页面上。这效果归功于KnockoutJs实现的双向绑定机制。
采用这种方式,对于程序开发也简单了,Web API只负责提供数据,而前端页面也减少了很多DOM操作。由于DOM操作比较繁琐和容易出错。这样也意味着减少了程序隐性的bug。并且,一个后端服务,可以供手机、Web浏览器和平台多个平台使用,避免重复开发。
五、总结
到此,本文的介绍就介绍了。本篇主要介绍了使用KnockoutJs来完成一个SPA程序。其实在实际工作中,打造单页面程序的模式更多的采用AngularJS。然后使用KnockoutJs也有很多,但是KnockoutJs只是一个MVVM框架,其路由机制需要借助其他一些类库,如我们这里使用Asp.net MVC中的路由机制,你还可以使用director.js前端路由框架。相对于KnockoutJs而言,AngularJs是一个MVVM+MVC框架。所以在下一个专题将介绍使用如何使用AngularJs打造一个单页面程序(SPA)。本文所有源码下载:
如果大家还想深入学习,可以点击进行学习,再为大家附3个精彩的专题:
以上就是本文的全部内容,希望对大家的学习有所帮助。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!