Home >Web Front-end >JS Tutorial >Backbone.js Simple Getting Started Example
Backbone is simple and flexible, and can be used in both rich JS applications and corporate websites. Compared with React’s design for View and one-way data flow, Backbone better embodies the idea of MVC, so I will write an introductory example for it. , friends in need can refer to it, I hope it can help everyone.
I wrote an article when I first started using the front-end MVC framework in 2011. Knockout and Backbone were both used at that time, but all subsequent projects used Backbone, mainly because it is simple and flexible, whether it is rich JS It can be used for both applications and corporate websites. Compared with React's design for View and one-way data flow, Backbone can better embody the idea of MVC, so I wrote an introductory example for it, with the following description:
1. The structure is divided into 4 sections, introducing Model/ View/Collection, to obtain data from remote, display it in the table and modify and delete it;
2. It is called "example", so the code is mainly. The first code of each section is the complete code, which can be used by copying and pasting. Each piece of code is written based on the previous piece of code, so the new content of each piece of code will not exceed 20 lines (including braces);
3. There are no comments for each line of code, but the important content is written after Specific instructions;
4. The development environment is Chrome, and the API of github is used, so that Chrome can obtain data even in a local path (path in the form of file://).
0. Introduction
Almost all frameworks do two things: one is to help you write the code in the right place; the other is to help you do some dirty work. Backbone implements a clear MVC code structure and solves the problem of data model and view mapping. Although all JS-related projects can be used, Backbone is most suitable for scenarios where a large amount of page content (mainly HTML) needs to be generated using JS, and users have a lot of interactions with page elements.
Backbone object has 5 important functions, Model/Collection/View/Router/History. Router and History are optimized for web applications. It is recommended to be familiar with pushState related knowledge first. In the entry stage, you can only understand Model/Collection/View. Think of Model as the core, Collection as a collection of Models, and View as a reflection of Model changes on the front end.
1. Model
Model is the core of all JS applications. Many Backbone tutorials like to start with View. In fact, View does not have much content, and understanding View is of little significance. Understanding Model is more important. important. The following code implements obtaining a gist information from the github API and displaying it on the page:
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script> <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script> <script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script> <link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> </head> <body> <table id="js-id-gists" class="table"> <thead><th>description</th><th>URL</th><th>created_at</th></thead> <tbody></tbody> </table> <script type="text/javascript"> var Gist = Backbone.Model.extend({ url: 'https://api.github.com/gists/public', parse: function (response) { return (response[0]); } }), gist = new Gist(); gist.on('change', function (model) { var tbody = document.getElementById('js-id-gists').children[1], tr = document.getElementById(model.get('id')); if (!tr) { tr = document.createElement('tr'); tr.setAttribute('id', model.get('id')); } tr.innerHTML = '<td>' + model.get('description') + '</td><td>' + model.get('url') + '</td><td>' + model.get('created_at') + '</td>'; tbody.appendChild(tr); }); gist.fetch(); </script> </body> </html>
LINE4~8: Load the JS library to be used. Ajax requests and some View functions require jQuery support (or rewriting ajax/View functions); Backbone's code is based on Underscore (or replaced by Lo-Dash); bootstrap.css is loaded just because the default style is too ugly...
LINE16~22: Create a Model and instantiate it. url is the address of the data source (API interface), and parse is used to process the returned data. What is actually returned is an Array, here we take the first Object.
LINE24~33: Bind change event. I haven't used View yet, so I have to handle the HTML myself. These 10 lines of code are mainly the usage of get (model.get), and other functions will be implemented using View later.
LINE34: Execute fetch. Obtain data from the remote, and the change event will be triggered after the data is obtained. You can override the sync method
Open Chrome's Console, enter gist, you can see the attributes obtained by the Model:
##Model provides data and data-related logic. The attributes output in the above picture are data. The fetch/parse/get/set in the code all operate on data. Others include escape/unset/clear/destroy. You can roughly understand its purpose from the function name. There is also a very commonly used validate function, which is used for data verification during set/save operations. Failure in verification will trigger the invalid event:/* 替换之前代码的JS部分(LINE16~34) */ var Gist = Backbone.Model.extend({ url: 'https://api.github.com/gists/public', parse: function (response) { return (response[0]); }, defaults: { website: 'dmyz' }, validate: function (attrs) { if (attrs.website == 'dmyz') { return 'Website Error'; } } }), gist = new Gist(); gist.on('invalid', function (model, error) { alert(error); }); gist.on('change', function (model) { var tbody = document.getElementById('js-id-gists').children[1], tr = document.getElementById(model.get('id')); if (!tr) { tr = document.createElement('tr'); tr.setAttribute('id', model.get('id')); } tr.innerHTML = '<td>'+ model.get('description') +'</td><td>'+ model.get('url') +'</td><td>'+ model.get('created_at') +'</td>'; tbody.appendChild(tr); }); gist.save();Compared with the previous code, there are 4 changes: LINE7~9: Added defaults. If there is no website in the attribute (note that the website value is not empty), the website value will be set to dmyz.
LINE10~14: Add validate function. When the website value is dmyz, the invalid event is triggered.
LINE18~20: Bind invalid event, error returned by alert.
LINE31: Do not perform fetch, save operation directly.
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script> <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script> <script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script> <link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> </head> <body> <table id="js-id-gists" class="table"> <thead><th>description</th><th>URL</th><th>created_at</th><th></th></thead> <tbody></tbody> </table> <script type="text/javascript"> var Gist = Backbone.Model.extend({ url: 'https://api.github.com/gists/public', parse: function (response) { return response[0]; } }), gist = new Gist(); var GistRow = Backbone.View.extend({ el: 'tbody', MODEL: gist, events: { 'click a': 'replaceURL' }, replaceURL: function () { this.MODEL.set('url', 'http://dmyz.org'); }, initialize: function () { this.listenTo(this.MODEL, 'change', this.render); }, render: function () { var model = this.MODEL, tr = document.createElement('tr'); tr.innerHTML = '<td>' + model.get('description') + '</td><td>' + model.get('url') + '</td><td>' + model.get('created_at') + '</td><td><a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" >®</a></td>'; this.el.innerHTML = tr.outerHTML; return this; } }); var tr = new GistRow(); gist.fetch(); </script> </body> </html>
LINE25: 所有的View都是基于DOM的,指定el会选择页面的元素,指定tagName会创建相应的DOM,如果都没有指定会是一个空的p。
LINE27~32: 绑定click事件到a标签,replaceURL函数会修改(set)url属性的值。
LINE33~35: View的初始化函数(initialize),监听change事件,当Model数据更新时触发render函数。
LINE36~42: render函数。主要是LINE41~42这两行,把生成的HTML代码写到this.el,返回this。
LINE44: 实例化GistRow,初始化函数(initialize)会被执行。
点击行末的a标签,页面显示的这条记录的URL会被修改成http://dmyz.org。
这个View名为GistRow,选择的却是tbody标签,这显然是不合理的。接下来更改JS代码,显示API返回的30条数据:
/* 替换之前代码的JS部分(LINE16~45) */ var Gist = Backbone.Model.extend(), Gists = Backbone.Model.extend({ url: 'https://api.github.com/gists/public', parse: function (response) { return response; } }), gists = new Gists(); var GistRow = Backbone.View.extend({ tagName: 'tr', render: function (object) { var model = new Gist(object); this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td></td>' return this; } }); var GistsView = Backbone.View.extend({ el: 'tbody', model: gists, initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function () { var html = ''; _.forEach(this.model.attributes, function (object) { var tr = new GistRow(); html += tr.render(object).el.outerHTML; }); this.el.innerHTML = html; return this; } }); var gistsView = new GistsView(); gists.fetch();
LINE2~9: 创建了两个Model(Gist和Gists),parse现在返回完整Array而不只是第一条。
LINE11~18: 创建一个tr。render方法会传一个Object来实例化一个Gist的Model,再从这个Model里get需要的值。
LINE26~34: 遍历Model中的所有属性。现在使用的是Model而不是Collection,所以遍历出的是Object。forEach是Underscore的函数。
Backbone的View更多的是组织代码的作用,它实际干的活很少。View的model属性在本节第一段代码用的是大写,表明只是一个名字,并不是说给View传一个Model它会替你完成什么,控制逻辑还是要自己写。还有View中经常会用到的template函数,也是要自己定义的,具体结合哪种模板引擎来用就看自己的需求了。
这段代码中的Gists比较难操作其中的每一个值,它其实应该是Gist的集合,这就是Backbone的Collection做的事了。
3. Collection
Collection是Model的集合,在这个Collection中的Model如果触发了某个事件,可以在Collection中接收到并做处理。第2节的代码用Collection实现:
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script> <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script> <script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script> <link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> </head> <body> <table id="js-id-gists" class="table"> <thead><th>description</th><th>URL</th><th>created_at</th><th></th></thead> <tbody></tbody> </table> <script type="text/javascript"> var Gist = Backbone.Model.extend(), Gists = Backbone.Collection.extend({ model: Gist, url: 'https://api.github.com/gists/public', parse: function (response) { return response; } }), gists = new Gists(); var GistRow = Backbone.View.extend({ tagName: 'tr', render: function (model) { this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td></td>' return this; } }); var GistsView = Backbone.View.extend({ el: 'tbody', collection: gists, initialize: function () { this.listenTo(this.collection, 'reset', this.render); }, render: function () { var html = ''; _.forEach(this.collection.models, function (model) { var tr = new GistRow(); html += tr.render(model).el.outerHTML; }); this.el.innerHTML = html; return this; } }); var gistsView = new GistsView(); gists.fetch({reset: true}); </script> </body> </html>
LINE17~23: 基本跟第2节的第2段代码一样。把Model改成Collection,指定Collection的Model,这样Collectio获得返回值会自动封装成Model的Array。
LINE38: Collection和Model不同,获取到数据也不会触发事件,所以绑定一个reset事件,在之后的fetch操作中传递{reset: true}。
LINE42~45: 从Collection从遍历Model,传给GistRow这个View,生成HTML。
Collection是Backbone里功能最多的函数(虽然其中很多是Underscore的),而且只要理解了Model和View的关系,使用Collection不会有任何障碍。给Collection绑定各种事件来实现丰富的交互功能了,以下这段JS代码会加入删除/编辑的操作,可以在JSBIN上查看源代码和执行结果。只是增加了事件,没有什么新内容,所以就不做说明了,附上JSBIN的演示地址:http://jsbin.com/jevisopo/1
/* 替换之前代码的JS部分(LINE16~51) */ var Gist = Backbone.Model.extend(), Gists = Backbone.Collection.extend({ model: Gist, url: 'https://api.github.com/gists/public', parse: function (response) { return response; } }), gists = new Gists(); var GistRow = Backbone.View.extend({ tagName: 'tr', render: function (model) { this.el.id = model.cid; this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td><a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="js-remove">X</a> <a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="js-edit">E</a> </td>' return this; } }); var GistsView = Backbone.View.extend({ el: 'tbody', collection: gists, events: { 'click a.js-remove': function (e) { var cid = e.currentTarget.parentElement.parentElement.id; gists.get(cid).destroy(); gists.remove(cid); }, 'click a.js-edit': 'editRow', 'blur td[contenteditable]': 'saveRow' }, editRow: function (e) { var tr = e.currentTarget.parentElement.parentElement, i = 0; while (i < 3) { tr.children[i].setAttribute('contenteditable', true); i++; } }, saveRow: function (e) { var tr = e.currentTarget.parentElement, model = gists.get(tr.id); model.set({ 'description' : tr.children[0].innerText, 'url': tr.children[1].innerText, 'created_at': tr.children[2].innerText }); model.save(); }, initialize: function () { var self = this; _.forEach(['reset', 'remove', 'range'], function (e) { self.listenTo(self.collection, e, self.render); }); }, render: function () { var html = ''; _.forEach(this.collection.models, function (model) { var tr = new GistRow(); html += tr.render(model).el.outerHTML; }); this.el.innerHTML = html; return this; } }); var gistsView = new GistsView(); gists.fetch({reset: true});
Afterword
虽然是入门范例,但因为篇幅有限,有些基本语言特征和Backbone的功能不可能面面俱到,如果还看不懂肯定是我漏掉了需要解释的点,请(在Google之后)评论或是邮件告知。
Backbone不是jQuery插件,引入以后整个DOM立即实现增删改查了,也做不到KnockoutJS/AnglarJS那样,在DOM上做数据绑定就自动完成逻辑。它是将一些前端工作处理得更好更规范,如果学习前端MVC的目的是想轻松完成工作,Backbone可能不是最佳选择。如果有一个项目,100多行HTML和1000多行JS,JS主要都在操作页面DOM(如果讨厌+号连接HTML还可以搭配React/JSX来写),那就可以考虑用Backbone来重写了,它比其他庞大的MVC框架要容易掌握得多,作为入门学习也是非常不错的。
相关推荐:
javascript - 关于backbone.js里的model.set和model.get
The above is the detailed content of Backbone.js Simple Getting Started Example. For more information, please follow other related articles on the PHP Chinese website!