主干 JS简单入门示例
我在11年后第一次开始使用前端MVC框架的时候写过一篇文章。当时用的是敲除和主干,但后来的项目都用主干,主要是因为它简单灵活,既可以被丰富的JS应用使用,也可以被企业网站使用。与React针对View和单向数据流的设计相比,Backbone更能体现MVC的思想,所以为它写一个入口示例,如下所示:
1.该结构分为四个部分,引入了Model/View/Collection,实现了从远程获取的数据到表的显示、修改和删除;2.叫做“示例”,所以代码是主要的。每个部分的第一个代码是完整的,可以通过复制和粘贴来使用。每个代码都是基于之前的代码编写的,所以每个代码的新内容不会超过20行(包括花括号);3.每一行代码都没有注释,但重要内容后写具体说明;4.开发环境是Chrome,使用github API,这样即使在本地路径(比如file:///的路径)也可以用Chrome获取数据。
0.介绍
几乎所有的框架都在做两件事:一是帮助你把代码写在正确的地方;二是帮你干点脏活。主干实现了清晰的MVC代码结构,解决了数据模型和视图映射的问题。虽然所有与JS相关的项目都可以使用,但是主干网最适合这样的场景:JS需要生成大量的页面内容(主要是HTML),用户与页面元素有很多交互。
主干对象有五个重要功能,模型/集合/视图/路由器/历史。路由器和历史记录针对网络应用进行了优化。建议先熟悉一下pushState的知识。在开始阶段,您只能知道模型/集合/视图。模型被认为是核心,集合是模型的集合,视图是反映前端模型的变化。
1.模型
模型是所有JS应用的核心,很多主干教程都喜欢从View开始。其实View内容少,理解View意义不大,所以理解Model更重要。下面的代码实现了从github API获取一条gist信息并显示在页面上:
!DOCTYPE html htmlheadscript type=' text/JavaScript ' src=' http :https://code . jquery.com/jquery-1 . 11 . 1 . js '/script script type=' text/JavaScript ' src=' http 3360http://underscorejs . org/下划线-min . js '/script script type=' text/JavaScript ' src=' http :3358 Backbonemodel . extend({ URL : ' https://API . github.com/gist/public '),parse:函数(response){ return(response[0]);} }),Gist=new Gist();gist.on('change ',function(model){ var t body=document . getelementbyid(' js-id-gist ')。children[1],tr=document . getelementbyid(model . get(' id '));if(!tr){ tr=document . create element(' tr ');tr.setAttribute('id ',model . get(' id '));} tr . innerhtml=' TD ' model . get(' description ')'/tdtd ' model . get(' URL ')'/tdtd ' model . get(' created _ at ')'/TD ';t body . appendchild(tr);});gist . fetch();/script/body/htmlLINE4~8:加载要使用的JS库。ajax请求和一些View函数需要jQuery支持(或者重写ajax/View函数);主干的代码是基于下划线编写的(或者用Lo-Dash替换);加载bootstrap.css只是因为默认样式太难看…
LINE16~22:创建一个模型并实例化它。Url是数据源(API接口)的地址,解析用于处理返回的数据。实际返回的是一个数组,第一个对象在这里。
LINE24~33:绑定变更事件。我还没用过View,所以要自己处理HTML。这10行代码主要是get (model.get)的用法,其他功能后面会用View来实现。
行34:执行提取。从远程位置获取数据,这将触发更改事件。您可以覆盖同步方法
打开Chrome的控制台,输入gist,可以看到Model获得的属性:
模型提供数据和与数据相关的逻辑。上图中的输出属性是data,代码中的fetch/parse/get/set都是对数据进行操作,其他功能包括escape/unset/clear/destroy。它的用途可以从函数名中大致了解。还有一个常用的验证函数,用于设置/保存操作期间的数据验证。验证失败将触发无效事件:
/*替换前面代码的JS部分(第16 ~ 34行)*/var gist=backbone . model . extend({ URL : ' https://api.github.com/gists/public', parse 3360函数(response){ return(response[0]);},default s : { web site : ' dmyz ' },validate:函数(attrs) { if (attrs .网站=='dmyz') { return '网站错误';} } }),Gist=new Gist();gist.on('无效',函数(模型,错误){ alert(错误);});gist.on('change ',function(model){ var t body=document . getelementbyid(' js-id-gist ')。children[1],tr=document . getelementbyid(model . get(' id '));if(!tr){ tr=document . create element(' tr ');tr.setAttribute('id ',model . get(' id '));} tr . innerhtml=' TD ' model . get(' description ')'/tdtd ' model . get(' URL ')'/tdtd ' model . get(' created _ at ')'/TD ';t body . appendchild(tr);});gist . save();与之前的代码相比,有四个变化:
LINE7~9:增加默认值。如果属性中没有网站(注意网站值不是空的),网站值将被设置为dmyz。LINE10~14:添加验证功能。当网站值为dmyz时,会触发无效事件。LINE18~20:绑定无效事件,警报返回错误。LINE31:不提取,而是直接保存。
因为没有提取,所以页面上不会显示任何数据。执行保存操作时将调用validate函数,验证失败时将触发无效事件,警报将给出错误提示。同时,保存操作还会向Model的URL发送PUT请求。github API不处理PUT,所以会返回404错误。
在控制台中输入gist.set ('description ',' demo '),您可以看到页面元素会相应改变。执行gist.set ('description ',gist.previous ('description ')以恢复以前的值。这是模型和视图之间的映射,它仍然是自己实现的。下一部分将由主干视图实现。
2.视角
用主干视图重写前面的代码LINE24~33:
!DOCTYPE html html head script TYPe=' text/JavaScript ' src=' http :https://代码。jquery。com/jquery-1。11 .1 .js '/script脚本类型=' text/JavaScript ' src=' http 3360http://underscorejs。组织/下划线-敏。js '/script脚本类型=' text/JavaScript ' src=' http :3358 backbone model。扩展({ URL : ' https://API。github。com/gist/public ',parse:函数(响应){返回响应[0];} }),Gist=new Gist();var GistRow=主干View.extend({ el: 'tbody ',MODEL: gist,event s : { ' click a ' : ' replace URL ' },replaceURL: function () { this .MODEL.set('url ',' http://dmyz。org’);},initialize:函数(){ this.listenTo(this .模型,“改变”,这个。渲染);},render:函数(){ var模型=这个.模型,tr=文档。创建元素(' tr ');tr。innerhtml=' TD '模型。获取(' description ')'/tdtd '模型。获取(' URL ')'/tdtd '模型。get(' created _ at ')'/TDA href=' JavaScript : void(0)' rel=' external nofollow ' rel=' external nofollow ' rel=' external nofollow '/a/TD ';这个。埃尔。innerHTMl=tr。OutHTMl归还这个;} });var tr=new GistRow();要点。fetch();/脚本/正文/htmlLINE25:所有的视角都是基于数字正射影像图的,指定埃尔会选择页面的元素,指定标记名会创建相应的多姆,如果都没有指定会是一个空的div。线路27~32:绑定点击事件到a标签,replaceURL函数会修改(设置)url属性的值线33~35:视图的初始化函数(初始化),监听变化事件,当模型数据更新时触发提出函数线路36~42:渲染函数。主要是第41~42行这两行,把生成的超文本标记语言代码写到这个。埃尔,返回这个。线路44:实例化GistRow,初始化函数(初始化)会被执行。
点击行末的a标签,页面显示的这条记录的统一资源定位器会被修改成http://dmyz.org。
这个视角名为GistRow,选择的却是tbody标签,这显然是不合理的。接下来更改射流研究…代码,显示应用程序接口返回的30条数据:
/* 替换之前代码的射流研究…部分(LINE16~45) */var Gist=主干Model.extend(),Gists=主干模型。扩展({ URL : ' https://API。github。com/gist/public '),parse:函数(响应){返回响应;} }),gist=new gist();var GistRow=主干视图.扩展({ tagName: 'tr ',render:函数(对象){ var模型=新Gist(对象);这个。埃尔。innerHTMl=' TD '模型。获取(' description ')'/tdtd '模型。获取(' URL ')'/tdtd '模型。get(' created _ at ')'/tdtd/TD '返回此;} });var GistsView=主干View.extend({ el: 'tbody ',model: gists,initialize : function(){ this。listento(这个。模型,‘改变’,这个。渲染);},render:函数(){ var html=_。forEach(this.model.attributes,function(object){ var tr=new GistRow();html=tr。渲染(对象。埃尔。OuthHTML});这个。埃尔。innerHTMl=html归还这个;} });var gist view=new gist view();要点。fetch();LINE2~9:创建了两个模型(要点和Gists),解析现在返回完整排列而不只是第一条线路11~18:创建一个tr。提出方法会传一个目标来实例化一个要点的模型,再从这个模型里得到需要的值LINE26~34:遍历模型中的所有属性。现在使用的是模型而不是收藏,所以遍历出的是对象。为每一个是强调的函数。
毅力的视角更多的是组织代码的作用,它实际干的活很少视图的模型属性在本节第一段代码用的是大写,表明只是一个名字,并不是说给视角传一个模型它会替你完成什么,控制逻辑还是要自己写。还有视角中经常会用到的模板函数,也是要自己定义的,具体结合哪种模板引擎来用就看自己的需求了。
这段代码中的Gists比较难操作其中的每一个值,它其实应该是要点的集合,这就是毅力的募捐做的事了。
3.募捐
募捐是模型的集合,在这个募捐中的模型如果触发了某个事件,可以在募捐中接收到并做处理。第2节的代码用募捐实现:
!DOCTYPE html html head script TYPe=' text/JavaScript ' src=' http :https://代码。jquery。com/jquery-1。11 .1 .js '/script脚本类型=' text/JavaScript ' src=' http 3360http://underscorejs。组织/下划线-敏。js '/script脚本类型=' text/JavaScript ' src=' http :3358 backbonemodel . extend(),Gists=主干收藏。扩展({模型: Gist,URL : ' https://API。github。com/Gists/public ',parse:函数(响应){返回响应;} }),gist=new gist();var GistRow=主干View.extend({ tagName: 'tr ',render :函数(模型){ this。埃尔。innerhtml=' TD '模型。获取(' description ')'/tdtd '模型。获取(' URL ')'/tdtd '模型。get(' created _ at ')'/tdtd/TD '返回此;} });var GistsView=主干View.extend({ el: 'tbody ',collection: gists,initialize : function(){ this。listento(这个。收藏,‘重置’,这个。渲染);},render:函数(){ var html=_。forEach(this.collection.models,function(model){ var tr=new GistRow();html=tr。渲染(模型。埃尔。OuthHTML});这个。埃尔。innerHTMl=html归还这个;} });var gist view=new gist view();吉斯茨。fetch({ reset 3360 true });/脚本/正文/html第17 ~ 23:行基本跟第2节的第2段代码一样。把模型改成收藏,指定募捐的模型,这样集体获得返回值会自动封装成模型的数组. LINE38:集合和模型不同,获取到数据也不会触发事件,所以绑定一个重置事件,在之后的取得操作中传递{ reset : true } . LINE 42 ~ 45:从募捐从遍历模型,传给GistRow这个查看,生成超文本标记语言。
募捐是毅力里功能最多的函数(虽然其中很多是强调的),而且只要理解了模型和视角的关系,使用募捐不会有任何障碍。给募捐绑定各种事件来实现丰富的交互功能了,以下这段射流研究…代码会加入删除/编辑的操作,可以在JSBIN上查看源代码和执行结果。只是增加了事件,没有什么新内容,所以就不做说明了,附上JSBIN的演示地址:http://jsbin.com/jevisopo/1
/* 替换之前代码的射流研究…部分(LINE16~51) */var Gist=主干Model.extend(),Gists=主干收藏。扩展({模型: Gist,URL : ' https://API。github。com/Gists/public ',parse:函数(响应){返回响应;} }),gist=new gist();var GistRow=主干视图.扩展({ tagName: 'tr ',render:函数(模型){这个。埃尔。id=型号。cid这个。埃尔。innerHTMl=' TD '模型。获取(' description ')'/tdtd '模型。获取(' URL ')'/tdtd '模型。get(' created _ at ')'/TDT TDA href=' JAVAScript : void(0)' rel=' external nofollow ' rel=' external nofollow ' rel=' external nofollow ' class=' js-remove ' x/a href=' JAVAScript : void(0)' rel=' external nofollow ' rel=' external nofollow ' });var GistsView=主干View.extend({ el: 'tbody ',collection: gists,event 3360 { ' click a . js-remove ' : function(e){ var cid=e . current target。parentelement。parentelement。id;要点。获取(cid ).销毁();要点。移除(cid);},'单击a.js-edit': 'editRow ',' blur TD[内容可编辑]' : ' saveRow ' },editRow:函数{ var tr=e . currenttarget。parentelement。parentelement,I=0;而(i 3) { tr.children[i].setAttribute('contenteditable ',true);我;} },saveRow:函数{ var tr=e . CurrentTarget。ParentElement,model=gist。get(tr。id);模特。set({ ' description ' : tr。儿童[0]).内部文本,“网址”: tr。儿童.innerText,' created_at': tr.children[2].innerText });模特。save();},初始化:函数(){ var self=this_.forEach(['重置','移除','范围'],函数{自我。listento(self。收集,e,自我。渲染);});},render:函数(){ var html=_。forEach(this.collection.models,function(model){ var tr=new GistRow();html=tr。渲染(模型。埃尔。OuthHTML});这个。埃尔。innerHTMl=html归还这个;} });var gist view=new gist view();吉斯茨。fetch({ reset 3360 true });编后记
虽然是入门范例,但因为篇幅有限,有些基本语言特征和毅力的功能不可能面面俱到,如果还看不懂肯定是我漏掉了需要解释的点,请(在谷歌之后)评论或是邮件告知。
毅力不是jQuery插件,引入以后整个数字正射影像图立即实现增删改查了,也做不到KnockoutJS/AnglarJS那样,在数字正射影像图上做数据绑定就自动完成逻辑。它是将一些前端工作处理得更好更规范,如果学习前端手动音量调节的目的是想轻松完成工作骨干可能不是最佳选择。如果有一个项目,100多行超文本标记语言和1000多行JS,JS主要都在操作页面DOM(如果讨厌号连接超文本标记语言还可以搭配反应/JSX来写),那就可以考虑用毅力来重写了,它比其他庞大的手动音量调节框架要容易掌握得多,作为入门学习也是非常不错的。
版权声明:主干 JS简单入门示例是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。