0

0

backbone.js 简单入门实例

小云云

小云云

发布时间:2018-01-15 10:28:53

|

2556人浏览过

|

来源于php中文网

原创

backbone简单、灵活,无论是富js应用还是企业网站都用得上,相比react针对view和单向数据流的设计,backbone更能体现mvc的思路,所以针对它写一篇入门范例,需要的朋友可以参考下,希望能帮助到大家。

11年刚开始用前端MVC框架时写过一篇文章,当时Knockout和Backbone都在用,但之后的项目全是在用Backbone,主要因为它简单、灵活,无论是富JS应用还是企业网站都用得上。相比React针对View和单向数据流的设计,Backbone更能体现MVC的思路,所以针对它写一篇入门范例,说明如下:

1. 结构上分4节,介绍Model/View/Collection,实现从远程获取数据显示到表格且修改删除;
2. 名为“范例”,所以代码为主,每节的第1段代码都是完整代码,复制粘贴就能用,每段代码都是基于前一段代码来写的,因此每段代码的新内容不会超过20行(大括号计算在内);
3. 每行代码没有注释,但重要内容之后有写具体的说明;
4. 开发环境是Chrome,使用github的API,这样用Chrome即使在本地路径(形如file://的路径)也能获取数据。

0. Introduction

几乎所有的框架都是在做两件事:一是帮你把代码写在正确的地方;二是帮你做一些脏活累活。Backbone实现一种清晰的MVC代码结构,解决了数据模型和视图映射的问题。虽然所有JS相关的项目都可以用,但Backbone最适合的还是这样一种场景:需要用JS生成大量的页面内容(HTML为主),用户跟页面元素有很多的交互行为。

Backbone对象有5个重要的函数,Model/Collection/View/Router/History。Router和History是针对Web应用程序的优化,建议先熟悉pushState的相关知识。入门阶段可以只了解Model/Collection/View。将Model视为核心,Collection是Model的集合,View是为了实现Model的改动在前端的反映。

1. Model

Model是所有JS应用的核心,很多Backbone教程喜欢从View开始讲,其实View的内容不多,而且理解了View意义不大,理解Model更重要。以下代码实现从github的API获取一条gist信息,显示到页面上:

<!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: 加载要用到的JS库。ajax请求和部分View的功能需要jQuery支持(或者重写ajax/View的功能);Backbone的代码是基于Underscore写的(或者用Lo-Dash代替);加载bootstrap.css只是因为默认样式太难看…

LINE16~22: 创建一个Model并实例化。url是数据源(API接口)的地址,parse用来处理返回的数据。实际返回的是一个Array,这里取第一个Object。

LINE24~33: 绑定change事件。还没有使用View,所以要自己处理HTML。这10行代码主要是get的用法(model.get),其他的功能之后会用View来实现。

LINE34: 执行fetch。从远程获取数据,获到数据后会触发change事件。可以重写sync方法

打开Chrome的Console,输入gist,可以看到Model获得的属性:

Model提供数据和与数据相关的逻辑。上图输出的属性是数据,代码中的fetch/parse/get/set都是对数据进行操作,其他的还有escape/unset/clear/destory,从函数名字就大致可以明白它的用途。还有很常用的validate函数,在set/save操作时用来做数据验证,验证失败会触发invalid事件:

/* 替换之前代码的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();

跟之前的代码比较,有4处改动:

LINE7~9: 增加了defaults。如果属性中没有website(注意不是website值为空),会设置website值为dmyz。
LINE10~14: 增加validate函数。当website值为dmyz时,触发invalid事件。
LINE18~20: 绑定invalid事件,alert返回的错误。
LINE31: 不做fetch,直接save操作。

因为没有fetch,所以页面上不会显示数据。执行save操作,会调用validate函数,验证失败会触发invalid事件,alert出错误提示。同时save操作也会向Model的URL发起一个PUT请求,github这个API没有处理PUT,所以会返回404错误。

在Console中输入gist.set(‘description', ‘demo'),可以看到页面元素也会有相应的变化。执行gist.set(‘description', gist.previous(‘description'))恢复之前的值。这就是Model和View的映射,现在还是自己实现的,下一节会用Backbone的View来实现。

2. View

基于jQuery验证输入框简单实用
基于jQuery验证输入框简单实用

基于jQuery验证输入框简单实用

下载

用Backbone的View来改写之前代码LINE24~33部分:

<!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框架要容易掌握得多,作为入门学习也是非常不错的。

相关推荐:

使用Backbone.js创建一个增删改查表的实例代码

javascript - 关于backbone.js里的model.set和model.get

Backbone.js中的集合详解_其它

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
jquery插件有哪些
jquery插件有哪些

jquery插件有jQuery UI、jQuery Validate、jQuery DataTables、jQuery Slick、jQuery LazyLoad、jQuery Countdown、jQuery Lightbox、jQuery FullCalendar、jQuery Chosen和jQuery EasyUI等。本专题为大家提供jquery插件相关的文章、下载、课程内容,供大家免费下载体验。

155

2023.09.12

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

322

2023.10.13

jquery删除元素的方法
jquery删除元素的方法

jquery可以通过.remove() 方法、 .detach() 方法、.empty() 方法、.unwrap() 方法、.replaceWith() 方法、.html('') 方法和.hide() 方法来删除元素。更多关于jquery相关的问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

403

2023.11.10

jQuery hover()方法的使用
jQuery hover()方法的使用

hover()是jQuery中一个常用的方法,它用于绑定两个事件处理函数,这两个函数将在鼠标指针进入和离开匹配的元素时执行。想了解更多hover()的相关内容,可以阅读本专题下面的文章。

512

2023.12.04

jquery实现分页方法
jquery实现分页方法

在jQuery中实现分页可以使用插件或者自定义实现。想了解更多jquery分页的相关内容,可以阅读本专题下面的文章。

271

2023.12.06

jquery中隐藏元素是什么
jquery中隐藏元素是什么

jquery中隐藏元素是非常重要的一个概念,在使用jquery隐藏元素之前,需要先了解css样式中关于元素隐藏的属性,比如display、visibility、opacity等属性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

126

2024.02.23

jquery中什么是高亮显示
jquery中什么是高亮显示

jquery中高亮显示是指对页面搜索关键词时进行高亮显示,其实现办法:1、先获取要高亮显示的行,获取搜索的内容,再遍历整行内容,最后添加高亮颜色;2、使用“jquery highlight”高亮插件。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

180

2024.02.23

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

50

2026.01.13

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

796

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 5.3万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.1万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号