宝哥软件园

WebApi Bootstrap KnockoutJs创建一个单页程序

编辑:宝哥软件园 来源:互联网 时间:2021-10-30

一、前言

在前一个话题中,我快速介绍了一下KnockoutJs的相关知识点,还写了一些简单的例子。希望大家能通过这些例子,快速上手KnockoutJs。为了让大家清楚的看到KnockoutJs在实际项目中的应用,本课题将介绍如何使用WebAPI bootstrap敲除js Asp.net MVC创建单页Web程序。现在大多数公司的实际项目中也采用了这种模式。

二、SPA(单页)的好处在介绍具体实现之前,我觉得有必要详细介绍一下SPA。SPA,单页Web Application的缩写,是一个在用户与应用程序交互时加载单个HTML页面并动态更新页面的Web应用程序。一开始浏览器会加载必要的HTML、CSS和JavaScript,所有的操作都在这个页面上完成,这个页面是由JavaScript控制的。

单页程序的好处是:

更好的用户体验,让用户在Web app中感受到原生app的速度和流畅。将前后关注点分开,前端负责界面显示,后端负责数据存储和计算,各司其职,不会将前后逻辑混在一起。为了减轻服务器的压力,服务器只需要生成数据,不需要显示逻辑和页面逻辑,从而增加了服务器的吞吐量。在MVC中,Razor语法编写的前端需要服务器完成页面合成,然后输出。同一套后端程序可以直接用于Web界面、手机、平板等各种客户端,无需修改。

当然,除了上面列出的优点,单页程序也有其缺点:

对SEO不好。这一点,如果是管理系统,没有影响,初始加载时间相对增加。因为所有的JS和CSS资源都会第一时间加载,这样会让后面的页面流畅。为此,您可以使用Asp.net MVC中的Bundle来绑定文件。关于Bundle详细使用的参考文章有://www . JB 51 . net/article/84329 . htm、//www . JB 51 . net/article/84329 . htm和//www . JB 51 . net/article/82174 . htm,导航不可用。如果你必须导航,你需要自己前进和后退。为此,我们可以通过自己实现正向和反向功能来弥补。其实这就是手机网页现在做的事情,现在需要在上面导航。对于一些企业后台管理系统,这也是可以做到的。开发者的技能水平和开发成本都很高。对于这个,没问题。程序员需要不断学习充电。幸运的是,一些前端框架非常容易使用。第三,使用Asp.net MVC WebAPI bootstrap敲除JS实现SPA。

详细介绍了SPA的优缺点。接下来让我们用Asp.net MVC WebAPI BSKO实现一个单页程序,从而体验SPA的流畅度,对比原Asp.net MVC Razor页面的效果。

1.使用VS2013创建Asp.net web应用项目,并检查MVC和WebAPI类库。详见下图:

2.创建相应的仓库和模型。这是一个简单的任务管理系统。具体型号和仓库代码如下:

任务实体类实现:

Public enum taskstate {active=1,completed=2 }///summary///task entity///summary public class task { public int id { get;设置;}公共字符串名称{ get设置;}公共字符串Description { get设置;}公共DateTime CreationTime { get设置;}公共日期时间完成时间{ get设置;}公共字符串Owner { get设置;}公共TaskState State { get设置;}公共任务(){ CreationTime=DateTime。解析(日期时间。now . ToLongDateString());状态=任务状态。主动;}}任务仓储类实现:

///摘要///这里仓储直接使用示例数据作为演示,真实项目中需要从数据库中动态加载////摘要公共类任务库{ # region Static field private Static lazytask repository _ task repository=new lazytask repository(()=new task repository());公共静态任务存储库当前{ get { return _taskRepository .价值;} } #结束区域#区域域私有只读listask _ tasks=new listask(){ new Task { Id=1,Name='创建一个矿泉程序,描述='SPA(单页网页应用程序),SPA的优势就是少量带宽,平滑体验,所有者="努力学习",完成时间=日期时间。解析(日期时间。现在。添加日期(1)。ToString(CultureInfo .不变量文化))},新任务{ Id=2,名称='学习"敲门",描述="敲门"是一个视图模型类库,支持双向绑定,所有者='汤米李,完成时间=日期时间。解析(日期时间。现在。增加天数(2)。ToString(CultureInfo .不变量文化))},新任务{ Id=3,名称='学习' AngularJS ',描述='AngularJs '是视图模型框架,集视图模型和手动音量调节与一体",所有者="李志,完成时间=日期时间。解析(日期时间。现在。增加天数(3)。ToString(CultureInfo .不变量文化))},新任务{ Id=4,名称='学习ASP .会员管理系统网站,描述='一瞥'是一款。网下的性能测试工具,支持ASP。NET 、asp.net最有价值球员,英孚等等,优势在于,不需要修改原项目任何代码,且能输出代码执行各个环节的执行时间,所有者='李术国,完成时间=日期时间。解析(日期时间。现在。增加天数(4)。ToString(CultureInfo .不变量文化))},};# end region # region Public Methods Public IEnumerableTask GetAll(){ return _ tasks;}公共任务获取(int id) { return _tasks .find(p=p . Id==Id);}公共任务添加(任务项){ if(item==null){ 0引发新的argumentNullException(' item ');}项Id=_tasks .数1;_任务。添加(项目);退货项目;}公共void Remove(int id){ _ tasks .全部删除(p=p . Id==Id);}公共bool Update(任务项){ if(item==null)}引发新的argumentNullException(' item ');} var taskItem=Get(item .id);if(TaskItem==null){ return false;} _任务。移除(TaskItem);_任务。添加(项目);返回真;} #endregion }3 .通过框架添加引导程序和击倒对手库。

4.实现后端数据服务。这里后端服务使用Asp.net网络应用程序接口实现的。具体的实现代码如下:

///摘要///任务WebAPI,提供数据服务////摘要公共类任务控制器: API控制器{私有只读任务存储库_任务存储库=任务存储库.当前;public IEnumerableTask GetAll(){ return _ task repository .GetAll().订单人(a=a . Id);}公共任务get(int id){ var item=_ Task repository .get(id);if(item==null){ 0引发新的HttpStatusCode . HttpresponseException(HttpStatusCode .未找到);}退货项目;}[Route(' API/tasks/GetByState ')]public IEnumerableTask GetByState(字符串状态){ IEnumerableTask结果=新列表任务();开关(状态. ToLower()){ case ' ' : case ' all ' :结果=_任务存储库.GetAll();打破;案例"活动":结果=_任务存储库.GetAll().其中(状态==任务状态.主动);打破;案例"已完成":结果=_任务存储库.GetAll().其中(状态==任务状态.已完成);打破;}结果=结果订单方(t=t . Id);返回结果;}[httpset]公共任务创建(任务项){ return _taskRepository .添加(项目);}[http put]公共void Put(任务项){ if(!_任务存储库.更新(项目)){ 0抛出新的HttpresponseException(Httpstatuscode .未找到);} } public void Delete(int id){ _ task repository .移除(id);} }5.使用Asp.net最有价值球员捆绑包对资源进行打包。对应的BundleConfig实现代码如下:

///摘要///只需要补充一些缺少的半铸钢钢性铸铁(铸造半钢)和射流研究…文件。因为创建模板的时候已经添加了一些半铸钢钢性铸铁(铸造半钢)和射流研究…文件////摘要公共类BundleConfig { //有关捆绑的更多信息,请访问http://go.microsoft.com/fwlink/?LinkId=301862公共静态void RegisterBundles(BundleCollection bundles){ bundles .添加(新的脚本包(' ~/bundle/jquery ').包括(' ~/Scripts/jquery-{version}).js’);捆绑包。添加(新的脚本包(' ~/bundles/jqueryval ').包括(' ~/Scripts/jquery。验证* ');//使用Modernizr的开发版本进行开发和学习。然后,当您准备好投入生产时,使用http://modernizr.com的构建工具只挑选您需要的测试。捆绑包。添加(新的脚本包(' ~/bundle/modernizr ').包括(' ~/Scripts/modernizr-*);捆绑包。添加(新的脚本包(' ~/bundle/bootstrap ').包括(' ~/Scripts/bootstrap.js ',' ~/Scripts/bootstrap-日期选择器。量滴js’);捆绑包。添加(新的StyleBundle('~/Content/css ').包括(' ~/Content/bootstrap.css ',' ~/Content/bootstrap-date picker 3。量滴CSS ',' ~/内容/网站。CSS ');捆绑包。添加(新的脚本包(' ~/bundle/敲除')。包括(' ~/Scripts/敲除-{version}).js ',' ~/Scripts/敲除。validation.min.js ',' ~/Scripts/敲除。最新地图。js’);捆绑包。添加(新的脚本包(' ~/bundle/app ').包含(' ~/脚本/应用/应用。js’);} }6.因为我们需要在页面上使得枚举类型显示为字符串。默认序列化时会将枚举转换成数值类型。所以要对WebApiConfig类做如下改动:

公共静态类WebApiConfig {公共静态void Register(HttpConfiguration config){//Web API配置和服务//Web API路由配置maphttpattributorates配置路线。MapHttpRoute(名称: ' DefaultAPI ',route templates : ' API/{ controller }/{ id } ',默认值3360 new { id=RouteParameter .可选});//使得序列化使用驼峰式大小写风格序列化属性配置格式化程序。jsonformatter。序列化程序设置。contract resolver=new camelocacepropertynamescontrolver();//将枚举类型在序列化时序列化字符串配置格式化程序。jsonformatter。序列化程序设置。转换器。add(new string numconverter());} }注:如果上面没有使用驼峰小写风格序列化的话,在页面绑定数据的时候也要进行调整。如绑定的名字属性的时候直接使用名字大写,如果使用名字方式会提示这个属性没有定义错误。由于射流研究…是使用驼峰小写风格对变量命名的。所以建议大家加上使用驼峰小写风格进行序列化,此时绑定的时候只能使用'姓名'这样的形式进行绑定。这样也更符合射流研究…代码的规范。

7.修改对应的布局文件和索引文件内容。

布局文件具体代码如下:

!DOCTYPE html html head meta charset=' utf-8 '/meta name=' viewport ' content=' width=device-width,initial-scale=1.0 ' title learning hard SPA Application/title @ Styles .呈现(' ~/Content/CSS ')@脚本render(' ~/bundle/modernizr ')/head body div class=' nav bar nav bar-reverse nav bar-fixed-top ' div class=' container ' div class=' nav bar-header ' p class=' nav bar-brand '简单任务管理系统/p/div class='导航条-折叠折叠ul class='导航条-导航' Li class=' active ' a href='/'主页/a/Li/ul/div/div/class=' container body-content ' id=' main ' @ render body()HR/footer p @ DateTime .现在。年学习硬矿泉应用/p/页脚/div/脚本渲染(' ~/bundle/jquery ')@脚本. 渲染(' ~/捆绑/引导')@脚本。渲染(' ~/捆绑/剔除')@脚本渲染(' ~/bundle/app ')/正文/HTMl索引页面代码如下:@{ ViewBag .标题="索引";布局=' ~/视图/共享/_布局。“cshtml”;} div id=' list ' data-bind='如果:可以创建' H2任务/H2 div class='响应表' table class='分条表'和tr th编号/th名称/th描述/th负责人/th创建时间/th完成时间/th状态/th/th/tr/ad t正文数据-绑定=' foreach : tasks ' tr TD数据-绑定=' text : id '/TD TDA数据-绑定=' text : name,单击: handlecreatorupdate '/a/TD TD TD数据-绑定=' text :描述'/TD TD TD数据-绑定=' text :所有者'/TD TD TD数据-绑定='文本3:创建时间'/TD TD TD数据事件){ settaskslist(' Completed ')} ' Completed/a/div class=' col-sm-2 col-sm-offset-6 ' a href=' JavaScript : void(0)' data-bind='单击: handlecreatorupdate '添加任务/a/div/div id=' create ' style='可视性:隐藏' H2添加任务/h2 br/div class=' form-horizontal ' div class=' form-group '标签为=' taskName '类=' col-sm-2控件-标签'名称*/label div class='col-sm-10 '输入类型=“文本”数据-bind=' value : ' name ' class=' form-control ' id=' taskName ' name=' taskName '占位符='名称/div/div class=' form-group '标签为=' tasksdesc ' class=' col-sm-2 control-label '描述/label div class=' col-sm-10 '文本区域class=' form-control '数据-bind=' value : description ' 行=' 3 ' id=' tasksdesc '名称=' tasksdessc '占位符='描述/文本区/div/div class='表单组'标签为=' Taskowner ' class=' col-sm-2 control-label '负责人*/label div class=' col-sm-10 ' input class=' form-control ' id=' tasksowner ' name=' tasksowner ' data-bind=' value : owner '占位符='负责人/div/div class=' form-group '的标签为=' TaskiFinish ' class=' col-sm-2 control-label '预计完成时间*/标签div类=' col-sm-10 ' input class=' form-control date picker ' id=' task finish ' data-bind=' value : finish time ' name=' task finish '/div/div class=' form-group '标签为=' tasksowner ' class=' col-sm-2 control-label '状态*/label div class=' col-sm-10 ' select id=' taskState ' class=' form-control ' data-bind=' value : state '选项活动/选项完成/选项/select/div/div class=' form-group div class=' col-sm-offset-2 col-sm-10 '按钮class=' BTN BTN-主'数据-绑定='单击3: handleBackClick保存单击'保存/按钮按钮数据-绑定='单击33: handleBackClick '创建对应的前端脚本逻辑。用射流研究…代码来请求数据,并创建对应视图模型对象来进行前端绑定。具体射流研究…实现代码如下:

var taskslistviewmodel={ tasks : ko。observablearray(),可以创建: ko。可观察(真)};var TaskMoDEL=function(){ this。id=0;这个。名称=ko。天文台();这个。描述=ko。天文台();这个。完成时间=ko。天文台();这个。所有者=ko。天文台();这个。状态=ko。天文台();这个。Fromjs=函数(数据){ this。id=数据。id;这个。名称(数据。姓名);描述(数据。描述);这个。完成时间(数据。完成时间);这个。所有者(数据。所有者);这个。状态(数据。国家);};};函数getAllTasks(){ sendAjaxRequest(' GET '),函数(数据){ taskslistviewmodel。任务。remove all();for(var I=0;一。数据。长度;I){ taskslistviewmodel。任务。推送(数据[I]);} },' GetByState ',{ ' state ' : ' all ' });}函数setTaskList(状态){ sendAjaxRequest('GET '),函数(数据){ taskslistviewmodel。任务。remove all();for(var I=0;一。数据。长度;I){ taskslistviewmodel。任务。推送(数据[I]);}},' GetByState ',{ ' state ' : state });}函数remove(item){ sendAjaxRequest(' DELETE '),函数(){ GetAllTasks();},项。id);} var task=新任务模型();函数handlecreatorupdate(item){ task。fromjs(项目);init date picker();taskslistviewmodel。cancreate(false);$('#create ').' CSS('可见','可见');}函数handleBackClick(){ taskslistviewmodel。cancreate(真);$('#create ').css(“”可见性','隐藏');}函数handleSaveClick(项){ if(项。id==undefined){ sendAjaxRequest(' POST '),函数(newItem) { //newitem是返回的对象taskslistviewmodel。任务。推送(新项目);},null,{ name: item.name,description : item。描述,完成时间:项。完成时间,所有者:项。所有者,状态:项。state });} else { sendAjaxRequest('PUT '),function(){ getAllTasks();},null,{ id:item.id,name: item.name,description : item。描述,完成时间:项。完成时间,所有者:项。所有者,状态:项。state });} TaskListViewMoDEL。Cancreate(真);$('#create ').css(“”可见性','隐藏');}函数sendAjaxRequest(httpMethod,回调,url,reqData) { $ .ajax('/api/tasks' (url?/' url : ' '),{ type: httpMethod,success:回调,数据: req data });} var initdate picker=function(){ $(' # create .日期选择器').日期选择器({ auto close : true });};$('.nav ').on('click ',' li ',function() { $(').nav li.active ').移除CLaSS(' active ');$(这个)。添加CLaSS(' active ');});$(文档)。ready(function(){ GetAllTasks();//使用击倒对手进行绑定柯。applybindings(TaskListViewMoDEL,$(“# list”).get(0));ko.applyBindings(任务,$('#create ').get(0));});到此,我们的单页面程序就开发完毕了,接下来我们来运行看看其效果。

从上面运行结果演示图可以看出,一旦页面加载完之后,所有的操作都好像在一个页面操作,完全感觉浏览器页面转圈的情况。对比于之前使用Asp.net最有价值球员剃须刀开发的页面,你是否感觉了矿泉的流畅呢?之前使用Asp.net最有价值球员剃须刀开发的页面,你只要请求一个页面,你就可以感受整个页面刷新的情况,这样用户体验非常不好。

四、与剃刀开发模式进行对比相信大家从效果上已经看出矿泉优势了,接下来我觉得还是有必要与传统实现网页面方式进行一个对比。与剃刀开发方式主要有以下2点不同:

1.页面被渲染的时候,数据在浏览器端得到处理。而不是在服务器上。将渲染压力分配到各个用户的浏览器端,从而减少网站服务器的压力。换做是剃刀语法,前端页面绑定语句应该就是如下:

@Model IEnumerableKnockoutJSSPA .模型。任务@foreach(模型中的定义变量项目){ tr td@item.Name/td td@item.Description/td/tr }这些都是在服务器端由剃刀引擎渲染的。这也是使用剃刀开发的页面会看到页面转圈的情况的原因。因为你每切换一个页面的时候,都需要请求服务端进行渲染,服务器渲染完成之后再将超文本标记语言返回给客户端进行显示。

2.绑定数据是动态的。这意味着数据模型中的变化会立即反映在页面上。这种效果归因于由KnockoutJs实现的双向绑定机制。

这样程序开发也简单,Web API只负责提供数据,首页也减少了很多DOM操作。因为DOM操作繁琐,容易出错。这也意味着程序隐藏的bug减少了。此外,后端服务可以被手机、网络浏览器和平台使用,以避免重复开发。

5.综上所述,本文的引言是这样介绍的。本文主要介绍了使用KnockoutJs来完成一个SPA程序。其实在实际工作中,AngularJS更多的是用来创建单页程序。然后是KnockoutJs的很多用途,但是KnockoutJs只是一个MVVM框架,它的路由机制需要其他类库。比如我们这里用的是Asp.net MVC中的路由机制,你也可以用director.js的前端路由框架,和KnockoutJs相比,AngularJs是一个MVVM MVC框架。因此,在下一个主题中,我们将介绍如何使用AngularJs创建单页程序(SPA)。

下载本文所有的源代码:SPAWithKnockoutJs。

如果你还想深入学习,可以点击这里学习,然后为你附上3个精彩话题:

引导教程。

自举实用教程。

引导插件教程。

以上就是本文的全部内容,希望对大家的学习有所帮助。

更多资讯
游戏推荐
更多+