Chinaunix首页 | 论坛 | 博客
  • 博客访问: 817947
  • 博文数量: 62
  • 博客积分: 526
  • 博客等级: 二等列兵
  • 技术积分: 2078
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-04 20:41
个人简介

博客迁移至 freefe.cc

文章分类

全部博文(62)

分类: JavaScript

2013-05-31 15:35:13


backbone 简介


当我们在开发大量 JavaScript 的 web 应用的时候,很大的工作就是处理 DOM 以及 DOM 中数据的问题。如果没有很好的组装架构,那么就会带来混乱的结构与越来越复杂和麻烦的问题。

backbone 是一个重量级的 JavaScript 应用框架。
为复杂的 JavaScript 应用程序提供了模型(models)、集合(collections)、视图(views)的结构。
  • 模型:用于绑定键值数据和自定义事件
  • 集合:附加有可枚举函数的丰富API
  • 视图:声明事件处理函数,通过RESRful JSON接口连接到应用程序。

backbone.js 对于 Underscore.js 是重度依赖,对于RESTful,history则依赖与
Backbone.Router,DOM处理依赖于 Backbone.View,json2.js,Jquery或者Zepto。
Backbone 将数据呈现为模型,可以创建模型、验证模型、销毁模型和保存模型至服务器。当 UI 的改变引起模型属性变化的时候就会触发 "change" 事件,所显示模型数据的 视图 会接受到更改通知,重新渲染。

backbone 使用


backbone.Events

backbone 中的 event 模块可以被拓展到任意对象,使任何对象都可以使用自定义事件。

  1. var Events = Backbone.Events = {

  2.     // 对一个事件绑定回调函数. 传递 "all" 则将绑定回调在所有事件触发时调用
  3.     on: function(name, callback, context) {

  4.       // API 检测 
  5.       if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;

  6.       //相当于 this._events = this._events || {} 下面语法更容易用来赋值 如下下句
  7.       //在绑定时间的对象中 建立事件池 来进行事件管理
  8.       this._events || (this._events = {});

  9.       // name 事件在事件池中的形式(数组形式) 存放当前对象绑定在name的所有事件
  10.       var events = this._events[name] || (this._events[name] = []);
  11.       // 将当前需要绑定的事件 push到事件池中的具体事件名称中
  12.       events.push({callback: callback, context: context, ctx: context || this});
  13.       return this;
  14.     },
  15.     off: function(){},
  16.     once: function(){},
  17.     trigger: function(){},
  18.     stopListening: function(){}
  19.   }
其实以上方法和 Jquery 的实现类似,只不过更为简单,Jquery 中还对当前需要绑定事件的对象如果为 DOM 元素的话需要进一步处理来保证 IE 中内存遇到的问题。


  1.     // 解绑一个或者多个回调.
  2.     // 如果 `context` 是 null, 移除所有有该函数的回调.
  3.     // 如果 `callback` 是 null, 移除该事件下的所有回调.
  4.     // 如果 `name` 是 null, 移除所有帮定的回调函数
  5.     off: function(name, callback, context) {
  6.       var retain, ev, events, names, i, l, j, k;
  7.       if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;

  8.       // obj.off() 移除所有事件
  9.       if (!name && !callback && !context) {
  10.         this._events = {};
  11.         return this;
  12.       }

  13.       // 使用 underscore 的 获取对象键值方法
  14.       names = name ? [name] : _.keys(this._events);
  15.       for (i = 0, l = names.length; i < l; i++) {
  16.         name = names[i];
  17.         // 移除某一事件下的回调
  18.         if (events = this._events[name]) {
  19.           this._events[name] = retain = [];
  20.           if (callback || context) {
  21.             for (j = 0, k = events.length; j < k; j++) {
  22.               ev = events[j];
  23.               if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
  24.                   (context && context !== ev.context)) {
  25.                 // 不是所需要删除的事件 则重新扔回 事件池中的对应名称中
  26.                 retain.push(ev);
  27.               }
  28.             }
  29.           }
  30.           //如果对应的名称中没有事件,那么删除事件池对象的该属性
  31.           if (!retain.length) delete this._events[name];
  32.         }
  33.       }

  34.       return this;
  35.     }
事件移除,简单地说因为事件绑定是使用了 事件池 的方法处理,那么对于移除事件只需要在事件池中 delete 掉响应的事件即可,唯一需要做的是兼容参数个数不同情况下的移除事件情况。


  1.     // 触发一个或多个事件, 触发所有绑定的回调.
  2.     // 除了事件名称,回调函数会被传递'trigger'相同的参数。
  3.     // (如果你监听了 'all', 会让你的回调函数将事件名称作为第一个参数).
  4.     // obj.trigger("change",function(){});
  5.     // obj.trigger("all",function(eventName){ alert(eventName) });
  6.     trigger: function(name) {
  7.       if (!this._events) return this;
  8.       var args = slice.call(arguments, 1);
  9.       if (!eventsApi(this, 'trigger', name, args)) return this;
  10.       var events = this._events[name];
  11.       //别忘了任何事件触发都要调用 all 中的事件
  12.       var allEvents = this._events.all;
  13.       if (events) triggerEvents(events, args);
  14.       if (allEvents) triggerEvents(allEvents, arguments);
  15.       return this;
  16.     },

  17.     // 使这个对象或者所有监听特定事件的对象停止监听该特定的事件
  18.     stopListening: function(obj, name, callback) {
  19.       var listeners = this._listeners;
  20.       if (!listeners) return this;
  21.       var deleteListener = !name && !callback;
  22.       if (typeof name === 'object') callback = this;
  23.       if (obj) (listeners = {})[obj._listenerId] = obj;
  24.       for (var id in listeners) {
  25.         listeners[id].off(name, callback, this);
  26.         if (deleteListener) delete this._listeners[id];
  27.       }
  28.       return this;
  29.     }
触发与停止监听。


  1.   // 分割事件字符串.
  2.   var eventSplitter = /s+/;

  3.   // 实现多样式化的事件功能的API
  4.   //比如现有API中的多名称的"change blur"` 和jquery风格的事件映射 `{change: action}`
  5.   var eventsApi = function(obj, action, name, rest) {
  6.     if (!name) return true;

  7.     // 处理事件映射
  8.     if (typeof name === 'object') {
  9.       for (var key in name) {
  10.         obj[action].apply(obj, [key, name[key]].concat(rest));
  11.       }
  12.       return false;
  13.     }

  14.     // 处理空间分割的事件名称.
  15.     if (eventSplitter.test(name)) {
  16.       var names = name.split(eventSplitter);
  17.       for (var i = 0, l = names.length; i < l; i++) {
  18.         obj[action].apply(obj, [names[i]].concat(rest));
  19.       }
  20.       return false;
  21.     }

  22.     return true;
  23.   };

  24.   // A difficult-to-believe, 在触发事件时优化内部调用. 尽可能快速到达最有可能的情况
  25.   // (核心的3个 Backbone 事件参数).
  26.   var triggerEvents = function(events, args) {
  27.     var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
  28.     switch (args.length) {
  29.       case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
  30.       case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
  31.       case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
  32.       case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
  33.       default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
  34.     }
  35.   };

  36.   var listenMethods = {listenTo: 'on', listenToOnce: 'once'};

  37.   // 使用listenTo 和 listenToOnce反转 `on` and `once` 控制. 将 *this* 对象监听另外一个对象中的事件
  38.   // 保持对监听的跟踪
  39.   _.each(listenMethods, function(implementation, method) {
  40.     Events[method] = function(obj, name, callback) {
  41.       var listeners = this._listeners || (this._listeners = {});
  42.       var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
  43.       listeners[id] = obj;
  44.       if (typeof name === 'object') callback = this;
  45.       obj[implementation](name, callback, this);
  46.       return this;
  47.     };
  48.   });

  49.   // 向后兼容的名称.
  50.   Events.bind = Events.on;
  51.   Events.unbind = Events.off;
使用的实例为

  1. var object = {};

  2. _.extend(object, Backbone.Events);

  3. object.bind("alert", function(msg) {
  4.   alert("Triggered " + msg);
  5. });

  6. object.trigger("alert", "");


  1. object.unbind("change", onChange); // 只移除onChange回调函数

  2. object.unbind("change"); // 移除所有 "change" 回调函数

  3. object.unbind();



backbone.sync


backbone.sync( method, model, [option] )
  •  method - CRUD 方法 ("create", "read", "update", 或 "delete") 
  •  model - 要被保存的模型(或要被读取的集合) 
  •  options - 成功和失败的回调函数,以及所有 jQuery 请求支持的选项
是对于模型在服务器中读取和保存的函数,都为 json 格式进行数据传输。默认情况下是依赖于 jQuery或者Zepto 的 Ajax 方法进行的发送 RESTful json 请求。(关于 REST Representational State Transfer 表现层状态转化 可见阮一峰老师的 理解RESTful架构)。额~反正本人不是很了解。

  1. // Backbone.sync 同步
  2.   // -------------

  3.   // 重载这个方法来改变 Backbone 持久模型在服务器中的方式、
  4.   // 通过请求类型和问题中的模型
  5.   // 默认情况发送 RESTful Ajax 请求到模型中的`url()`.
  6.   // 一些可行的自定义为:
  7.   //
  8.   // * 使用 `setTimeout` 在一个请求中批量的触发更新.
  9.   // * 发送 XML 而不是 JSON.
  10.   // * 坚持模型通过 WebSockets 而不是 Ajax.
  11.   //
  12.   // 开启 `Backbone.emulateHTTP` 为像 `POST` 一样发送 `PUT` 和 `DELETE` 请求
  13.   // `_method` 参数中包含真正的 HTTP 方法,
  14.   // 以及主体的所有请求 as `application/x-www-form-urlencoded`
  15.   // 替换为 `application/json`参数名为 `model`的模块.
  16.   // 当接口为服务器端语言,如**PHP**时很有用, 使得主体的'PUT'请求难以读取
  17.   Backbone.sync = function(method, model, options) {
  18.     var type = methodMap[method];

  19.     // 默认设置, 除非指定.
  20.     _.defaults(options || (options = {}), {
  21.       emulateHTTP: Backbone.emulateHTTP,
  22.       emulateJSON: Backbone.emulateJSON
  23.     });

  24.     // 默认 JSON-request 设置.
  25.     var params = {type: type, dataType: 'json'};

  26.     // 确保有一个 URL.
  27.     if (!options.url) {
  28.       params.url = _.result(model, 'url') || urlError();
  29.     }

  30.     // 确保我们有正确的请求数据.
  31.     if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
  32.       params.contentType = 'application/json';
  33.       params.data = JSON.stringify(options.attrs || model.toJSON(options));
  34.     }

  35.     // 对于老的服务器, 模拟JSON以HTML形式的.
  36.     if (options.emulateJSON) {
  37.       params.contentType = 'application/x-www-form-urlencoded';
  38.       params.data = params.data ? {model: params.data} : {};
  39.     }

  40.     // 对于老的服务器, 模拟 HTTP 通过用 `_method` 方法仿造 HTTP
  41.     // 和一个 `X-HTTP-Method-Override` 头.
  42.     if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
  43.       params.type = 'POST';
  44.       if (options.emulateJSON) params.data._method = type;
  45.       var beforeSend = options.beforeSend;
  46.       options.beforeSend = function(xhr) {
  47.         xhr.setRequestHeader('X-HTTP-Method-Override', type);
  48.         if (beforeSend) return beforeSend.apply(this, arguments);
  49.       };
  50.     }

  51.     // 在 non-GET 请求中不传递数据.
  52.     if (params.type !== 'GET' && !options.emulateJSON) {
  53.       params.processData = false;
  54.     }

  55.     // 如果我们发送 `PATCH` 请求,
  56.     // 我们在一个老版本ActiveX默认启动的情况下,使用XHR来取代jQuery方法。
  57.     // 删除它当IE8支持 `PATCH` 的时候.
  58.     if (params.type === 'PATCH' && window.ActiveXObject &&
  59.           !(window.external && window.external.msActiveXFilteringEnabled)) {
  60.       params.xhr = function() {
  61.         return new ActiveXObject("Microsoft.XMLHTTP");
  62.       };
  63.     }

  64.     //提出请求, 允许用户自定义Ajax选项.
  65.     var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
  66.     model.trigger('request', model, xhr, options);
  67.     return xhr;
  68.   };

  69.   // 映射 CRUD 到 HTTP 为了默认的 `Backbone.sync` 执行.
  70.   var methodMap = {
  71.     'create': 'POST',
  72.     'update': 'PUT',
  73.     'patch': 'PATCH',
  74.     'delete': 'DELETE',
  75.     'read': 'GET'
  76.   };

  77.   // 通过 `$` 代理来设置 `Backbone.ajax` 的默认执行.
  78.   // 如果想要使用另一个库那么重载它.
  79.   Backbone.ajax = function() {
  80.     return Backbone.$.ajax.apply(Backbone.$, arguments);
  81.   };


backbone 源码注释


以上为 bockbone 的2个核心的模块,另外模块将在下两篇中简单介绍。

 由于源码过长,请  。这里只为对 backbone 原文注释的简单翻译,具体还需要研究。

对于 backbone 的中文文档,请  这是一个不错的中文文档,各个接口均有详细说明。
阅读(5664) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

最代码2014-05-22 17:42:39

backbone代码下载:http://www.zuidaima.com/share/search.htm?key=backbone