Backbone ist einfach und flexibel und kann sowohl in umfangreichen JS-Anwendungen als auch auf Unternehmenswebsites verwendet werden. Im Vergleich zum React-Design für Ansicht und unidirektionalen Datenfluss verkörpert Backbone die Idee von MVC besser, daher werde ich eine schreiben Einführendes Beispiel dafür, Freunde in Not können sich darauf beziehen, ich hoffe, es kann allen helfen.
Ich habe einen Artikel geschrieben, als ich 2011 zum ersten Mal mit der Verwendung des Front-End-MVC-Frameworks begann. Damals wurden sowohl Knockout als auch Backbone verwendet, aber alle nachfolgenden Projekte verwendeten Backbone, hauptsächlich weil es einfach und flexibel ist Es ist reichhaltig JS Es kann sowohl für Anwendungen als auch für Unternehmenswebsites verwendet werden. Im Vergleich zum React-Design für View und unidirektionalen Datenfluss kann Backbone die Idee von MVC besser verkörpern, daher habe ich ein Einführungsbeispiel dafür geschrieben:
1 Die Struktur ist in 4 unterteilt Abschnitte, die Modell/Ansicht/Sammlung einführen, um Daten von der Fernbedienung abzurufen, sie in der Tabelle anzuzeigen und zu ändern und zu löschen.
2. Der Code ist hauptsächlich der erste Code in jedem Abschnitt Sie können den vollständigen Code kopieren und einfügen, der auf dem vorherigen Code basiert, sodass der neue Inhalt jedes Codes 20 Zeilen (einschließlich geschweifter Klammern) nicht überschreitet Es gibt keine Kommentare für jede Codezeile, aber wichtige Inhalte werden nach spezifischen Anweisungen geschrieben.
4. Die Entwicklungsumgebung ist Chrome und die API von Github wird verwendet, sodass Chrome Daten auch im lokalen Pfad (Pfad) abrufen kann in der Form file://).
<!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>
/* 替换之前代码的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();
ZEILE7~9: Standardeinstellungen hinzugefügt. Wenn das Attribut keine Website enthält (beachten Sie, dass der Website-Wert nicht leer ist), wird der Website-Wert auf dmyz gesetzt.
ZEILE10~14: Validierungsfunktion hinzufügen. Wenn der Website-Wert dmyz ist, wird das ungültige Ereignis ausgelöst.
ZEILE18~20: Ungültiges Ereignis binden, Fehler durch Warnung zurückgegeben.
ZEILE31: Kein Abruf, Vorgang direkt speichern.
<!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
Das obige ist der detaillierte Inhalt vonEinfaches Beispiel für den Einstieg in Backbone.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!