欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

簡單了解Backbone.js的Model模型以及View視圖的源碼

 更新時間:2016年02月14日 17:21:17   作者:qbright  
這篇文章主要簡單介紹了Backbone.js的Model模型以及View視圖的源碼,Backbone是一款高人氣JavaScript的MVC框架,需要的朋友可以參考下

Backbone.Model

今天我們先來談?wù)凚ackbone.js MVC 中的 M , Model是backbone的核心部分,包含著頁面展示內(nèi)容的數(shù)據(jù),還有圍繞著數(shù)據(jù)操作的各種 轉(zhuǎn)換,校驗,計算 ,權(quán)限控制,服務(wù)端交互等等操作,你可以通過 Backbone.Model.extend() 生成你的model , 當(dāng)然生成的model也可以作為一個基類去向下擴(kuò)展更多的model

 var People = Backbone.Model.extend({
     
 });

 var Man = People.extend({

 });

Backbone.Model Api

Backbone.Model 提供了大量方法用于實現(xiàn)一個Model的基本操作,當(dāng)然其中最基本的還是基于 Backbone.Events 的事件機(jī)制,在Model的attributes發(fā)生變化的時候,相應(yīng)的 change:attr事件會被觸發(fā),下面是提供的API:

2016214171632823.png (207×574)

其中有對數(shù)據(jù)進(jìn)行服務(wù)端操作的方法:

  • sync : 包裝了Backbone.sync,xhr的基類
  • fetch : 用于從服務(wù)端獲取數(shù)據(jù)
  • save : 向服務(wù)端持久化數(shù)據(jù)
  • destroy: 從服務(wù)端刪除數(shù)據(jù)

model中數(shù)據(jù)操作的方法:

  • get : 從attributes中獲取數(shù)據(jù)
  • set : 向attributes中設(shè)置數(shù)據(jù)
  • escape : 對數(shù)據(jù)進(jìn)行編碼 ,使用的是underscore的 _.escape
  • has : attributes中有無對應(yīng)數(shù)據(jù)
  • unset : 從attributes中刪除數(shù)據(jù)
  • clear : 清空attributes數(shù)據(jù)
  • changed : 與上個狀態(tài)(執(zhí)行過set,unset),相比變化的值
  • toJSON : 將 attributes 序列化成一個對象
  • parse : 當(dāng)設(shè)置項parse為真的時候,初始化/set/unset/fetch等數(shù)據(jù)操作中會對目標(biāo)數(shù)據(jù)進(jìn)行一個解析返回解析后的對象,此方法為空方法,需要重寫覆蓋
  • hasChanged : 與上個狀態(tài)(執(zhí)行過set,unset),相比是否發(fā)生過變化
  • changeAttributes : 與上個狀態(tài)(執(zhí)行過set,unset),相比發(fā)生的所有值
  • previous : 前一狀態(tài) (執(zhí)行過set,unset),該屬性對應(yīng)的值
  • previousAttributes : 與上個狀態(tài)(執(zhí)行過set,unset),發(fā)生過變化對象的前一個狀態(tài)的所有值

model中數(shù)據(jù)校驗的方法:

  • validate:用于對model中數(shù)據(jù)進(jìn)行校驗,需要重寫覆蓋默認(rèn)方法
  • validationError : 返回最近一個invalid時返回的值
  • isValid : 調(diào)用_validate方法

下面會針對一些重點的api進(jìn)行講解:

構(gòu)造函數(shù)

  var Model = Backbone.Model = function(attributes, options) {
     var attrs = attributes || {};
     options || (options = {});
     this.cid = _.uniqueId('c');
     this.attributes = {};
     if (options.collection) this.collection = options.collection;
     if (options.parse) attrs = this.parse(attrs, options) || {};
     attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
     this.set(attrs, options);
     this.changed = {};
     this.initialize.apply(this, arguments);
   };

構(gòu)造函數(shù)主要對初始化的數(shù)據(jù)和選項進(jìn)行設(shè)置,然后會對生成一個唯一的cid用于標(biāo)示model,如果options中的parse為true,那么會對初始化數(shù)值通過parse方法進(jìn)行一個解析,調(diào)用set方法,所有的初始值會被存入attributes中,調(diào)用initialize初始化方法 。model的初始化就完成了。

set

model.set(attributes, [options])

set方法會將值設(shè)置進(jìn)入attribute中,設(shè)置時如果設(shè)置了slient為true,會觸發(fā)相應(yīng)的 change:attr 的事件,最后統(tǒng)一觸發(fā)change事件,set方法部分代碼如下:

 

  set: function(key, val, options) {
     //......

      // key值可以是鍵值對,也可以是一個字符串,將賦值傳入attrs屬性中  
    if (typeof key === 'object') {
     attrs = key;
     options = val;
    } else {
     (attrs = {})[key] = val;
    }

   // ....

    //對設(shè)置的值進(jìn)行校驗 
      if (!this._validate(attrs, options)) return false;
    unset = options.unset; // unset為true時會刪除設(shè)置的值,unset方法就是通過 set(key,val,{unset:true})去實現(xiàn)的
   
    //當(dāng)對象正在被被設(shè)置的時候,不給 previousAttributes 賦值
    if (!changing) {
     this._previousAttributes = _.clone(this.attributes);
     this.changed = {};
    }
 
    current = this.attributes, prev = this._previousAttributes;
 
    //如果對Id進(jìn)行了設(shè)置,則對對象的id屬性也進(jìn)行改變
    if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
 

    //進(jìn)行 設(shè)置或者是刪除操作
    for (attr in attrs) {
     val = attrs[attr];
     if (!_.isEqual(current[attr], val)) changes.push(attr);
     if (!_.isEqual(prev[attr], val)) {
      this.changed[attr] = val;//為model的changed進(jìn)行設(shè)置
     } else {
      delete this.changed[attr];
     }
     unset ? delete current[attr] : current[attr] = val;//如果unset被設(shè)置成true了,則進(jìn)行刪除操作
    }
 
    //在silent不為false 的情況下,進(jìn)行change:attr事件發(fā)送
    if (!silent) {
     if (changes.length) this._pending = options;
     for (var i = 0, l = changes.length; i < l; i++) {
      this.trigger('change:' + changes[i], this, current[changes[i]], options);
     }
    }
 

    //觸發(fā)change事件
    if (changing) return this;
    if (!silent) {
     while (this._pending) {
      options = this._pending;
      this._pending = false;
      this.trigger('change', this, options);
     }
    }
    this._pending = false;
    this._changing = false;
    return this;
   
  }

set的整個流程就是 對傳入的數(shù)值進(jìn)行處理,變成一個鍵值對,然后對數(shù)值進(jìn)行校驗,檢查正確性,然后開始進(jìn)行設(shè)置操作,設(shè)置時檢查數(shù)值時候是發(fā)生改變的,如果有則加入一個 changeed的對象中,然后檢查unset的值,進(jìn)行相應(yīng)的添加更新刪除操作。然后依次觸發(fā)change:attr和change事件。

save

model.save([attributes], [options])

save方法用于向客戶端持久化數(shù)據(jù),會根據(jù)數(shù)據(jù)的不同和配置的不同選擇使用create,update或者是patch,并且觸發(fā) sync 事件,以下為部分代碼:

  save: function(key, val, options) {     
    // ......
 

 
    //當(dāng)設(shè)置了wait屬性true的時候 , save方法先不執(zhí)行set方法(不觸發(fā)change事件),只執(zhí)行validate
    if (attrs && !options.wait) {
     if (!this.set(attrs, options)) return false;
    } else {
     if (!this._validate(attrs, options)) return false;
    }

    //如果wait為true,設(shè)置this.attributes
    if (attrs && options.wait) {
     this.attributes = _.extend({}, attributes, attrs);
    }
 

    // .....
   
    var model = this;
    var success = options.success;
    options.success = function(resp) {
     // Ensure attributes are restored during synchronous saves.
     model.attributes = attributes;
     var serverAttrs = model.parse(resp, options);
     //如果wait為true , 那么會在請求返回之后才進(jìn)行set操作
     if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
     if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
      return false;
     }
     if (success) success(model, resp, options);
     //觸發(fā) sync 事件
     model.trigger('sync', model, resp, options);
    };

    //生成XHR onerror 回調(diào)函數(shù)
    wrapError(this, options);
    //選擇方法
    method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
    if (method === 'patch') options.attrs = attrs;
    xhr = this.sync(method, this, options);
 
    // Restore attributes.
    if (attrs && options.wait) this.attributes = attributes;
    //返回xhr對象
    return xhr;
  }

 
save 中最需要注意的就是 wait 的設(shè)置,當(dāng)wait為真的時候,save返回會在xhr返回之后再執(zhí)行set操作,而不是在xhr之前就進(jìn)行set操作,因此change事件的觸發(fā)時機(jī)也就不同了。

之前說過整個Backbone都是通過事件串聯(lián)起來的,所以對于事件觸發(fā)時機(jī)的了解和把握是非常重要的,不然會在開發(fā)過程中導(dǎo)致一些奇怪的問題出現(xiàn)。

Backbone.View
前面已經(jīng)對backbone中的Event、Model、Collection代碼進(jìn)行了分析,現(xiàn)在我們來看下MVC中的V部分,也就是Backbone.View,View在Backbone中主要用于溝通頁面中的DOM和Backbone.Model/Collection,頁面的邏輯操作,DOM事件的綁定等,View部分的代碼非常簡答,加上注釋只有110左右。 View部分有一下API:

2016214171843674.png (197×245)

方法不多,下面對部分API進(jìn)行介紹:

構(gòu)造方法

  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
 var View = Backbone.View = function(options) {
   this.cid = _.uniqueId('view');
   options || (options = {});
   _.extend(this, _.pick(options, viewOptions));
   this._ensureElement();
   this.initialize.apply(this, arguments);
   this.delegateEvents();
 };

構(gòu)造方法中為View生成了一個唯一的cid,以'view'開頭,然后進(jìn)行對目標(biāo)屬性viewOptions進(jìn)行合并,接著調(diào)用_ensureElement判斷el的情況,接著調(diào)用delegateEvents進(jìn)行方法綁定,初始化完成 。

delegateEvents

view.setElement(element)

   setElement: function(element, delegate) {
    if (this.$el) this.undelegateEvents();//如果已經(jīng)存在this.$el,進(jìn)行事件解綁

    //對$el進(jìn)行賦值,本質(zhì)是一個jquery或者是 Lo-Dash and Zepto 對象
    this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
    //把dom element 賦值給el
    this.el = this.$el[0];

     //如果沒有顯式傳值,則進(jìn)行事件綁定
    if (delegate !== false) this.delegateEvents();
    return this;
   }

setElement方法用于設(shè)置View對應(yīng)的element , 這個方法在new的時候會被調(diào)用, 如果想要在使用過程中改變View的dom元素指向,可調(diào)用這個方法進(jìn)行重新設(shè)置

_ensureElement

  _ensureElement: function() {
     //如果已經(jīng)對el進(jìn)行設(shè)置,直接調(diào)用setElement方法
    if (!this.el) {//如果沒有設(shè)置,生成一個元素對象,再調(diào)用setElement方法
     var attrs = _.extend({}, _.result(this, 'attributes'));
     if (this.id) attrs.id = _.result(this, 'id');
     if (this.className) attrs['class'] = _.result(this, 'className');
     var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
     this.setElement($el, false);
    } else {
     this.setElement(_.result(this, 'el'), false);
    }
  }

_ensureElement這個方法是內(nèi)部方法,在構(gòu)造函數(shù)中使用,用于判斷指定的el在頁面中存不存在,如果存在則對$el進(jìn)行賦值,如果不存在,則生成一個$el,但是要注意這個對象是沒有落地到dom樹中的 。

delegateEvents

delegateEvents([events])

    // *{"event selector": "callback"}*
   //
   //   {
   //    'mousedown .title': 'edit',
   //    'click .button':   'save',
   //    'click .open':    function(e) { ... }
   //   }

   delegateEvents: function(events) {
      //如果不存在events,則直接返回
      if (!(events || (events = _.result(this, 'events')))) return this;
   
      //先解除所有的事件綁定
      this.undelegateEvents();
   
      //處理每個事件
      for (var key in events) {
       var method = events[key];
       //解析回調(diào)函數(shù)
       if (!_.isFunction(method)) method = this[events[key]];
       if (!method) continue;
   
       //對選擇器進(jìn)行分析
       var match = key.match(delegateEventSplitter);
       var eventName = match[1], selector = match[2];
       method = _.bind(method, this);
   
       //綁定的事件名都是以 eventName + '.delegateEvents' + cid 組成,
       //這么做能夠在undelegateEvents的時候選擇到這個View的所有事件
       eventName += '.delegateEvents' + this.cid;
       if (selector === '') {
        this.$el.on(eventName, method);
       } else {
        this.$el.on(eventName, selector, method);
       }
      }
      return this;
   }

在View中你可以使用一個 key:value 集合指定對應(yīng)的事件,在初始化的時候構(gòu)造函數(shù)會調(diào)用delegateEvents進(jìn)行綁定,需要注意的是所有在key中指定的元素的父元素都必須是$el,也就是說元素必須是$el的子節(jié)點,否則綁定失敗。

View和其他backbone模塊一個區(qū)別就是沒有自己的內(nèi)建自定義事件,當(dāng)然他也組合了Events模塊,但是所有的事件都需要自己進(jìn)行建立。View主要是一個MVC模型的承載,其實真正的功能不多,其實從模型層面上看V在前端開發(fā)中是最接近業(yè)務(wù)邏輯的,所以在View中大部分的邏輯都是開發(fā)者自己去擴(kuò)展的。

相關(guān)文章

  • 全面解析JavaScript的Backbone.js框架中的Router路由

    全面解析JavaScript的Backbone.js框架中的Router路由

    這篇文章主要介紹了Backbone.js框架中的Router路由功能,Router在Backbone中相當(dāng)于一個MVC框架中的Controller控制器功能,需要的朋友可以參考下
    2016-05-05
  • 實例講解JavaScript的Backbone.js框架中的View視圖

    實例講解JavaScript的Backbone.js框架中的View視圖

    這篇文章主要介紹了實例講解JavaScript的Backbone.js框架中的View視圖,在瀏覽器端js框架backbone中我們用view來綁定和處理DOM事件,需要的朋友可以參考下
    2016-05-05
  • 最新評論