Backbone模型


現在進入最關鍵的組件 - 模型。模型用來存儲應用的所有數據,以及直接和數據操作相關的邏輯。Backbone中的模型類是Backbone.Model,它包含了數據存儲,數據驗證,以及數據發生變動時觸發相關動作。

一般可以把模型與后端綁定(ORM),模型改變的同時向后端發起請求(Ajax)更新數據(數據庫)。也有把模型和DOM元素綁定,模型改變時更新HTML界面。

 

模型

可以直接new一個Backbone.Model,它返回一個Model實例

var model = new Backbone.Model()
model.set({name: 'Backus', age: 35})

也可擴展Backbone.Model,定義自己的模型類(構造器)

var Person = Backbone.Model.extend({
    initialize: function(name, age) {
        this.set({name: name, age: age})
    }
})

extend的第一個參數為一個對象,它將成為模型實例的屬性。第二個參數將成為類屬性(類靜態屬性、方法)。這在 Backbone的寫類方式 有所提及。

 

模型與屬性 - set/get

使用set和get方法來設置或獲取模型的屬性。屬性在模型實例上有一個專門的屬性來存儲:this.attributes,set/get都圍繞this.attributes操作。

設置模型Person的屬性

var p1 = new Person()
p1.set({name: 'Backus', age: 87})

Firefox控制台使用get方法獲取屬性

set方法除了可以接受對象形式參數,也可以接受前兩個key,value方式。

set方法內部對此做了兼容,第一個參數key如果是對象類型,直接將該對象拷貝到this.attributes上,如果key是字符串,那么將在內部把key,value轉成一個臨時對象attrs再拷貝到this.attributes上。

 

set還有第三個可選參數options,如果設置了options.validate=true,且模型如果定義了validate方法,那么每次設置時將調用該方法進行校驗,校驗未通過將不進行后續設置,而直接返回。

var Person = Backbone.Model.extend({
    validate: function(attrs) {
        if ( !_.isString(attrs.name) ) return 'name 必須是字符串類型'
        if ( !_.isNumber(attrs.age) ) return 'age 必須是數字類型'
    }
})
var p1 = new Person()
p1.on('invalid', function(model, error, agr) {
    console.log(error)
})
p1.set({name: 'Backus', age: 87})

從控制台輸入如下

可以看到輸出了提示信息“name 必須是字符串類型”,再打印出p1的JSON格式

可以看到name仍然是“Backus”,並未修改。

 

在set方法內部會調用私有的this._validate方法,該方法如下

_validate: function(attrs, options) {
  if (!options.validate || !this.validate) return true;
  attrs = _.extend({}, this.attributes, attrs);
  var error = this.validationError = this.validate(attrs, options) || null;
  if (!error) return true;
  this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
  return false;
}

1.0與之前版本實現不同,必須顯示的設置options.validate=true,且模型必須實現this.validate方法,才會進行驗證,否則直接返回true。1.0之前默認就進行驗證,無需設置options.validate為true。驗證無效(失敗)后會派發“invalid”事件,因此可以監聽該事件做后續處理,比如顯示一些必要的提示信息。

 

默認情況下,set調用都會觸發“change”事件,如下

p1.on('change', function(model, error) {
    console.log('attributes has changed')
})
p1.set({name: 'Backus', age: 87})

你可以在回調函數中去更新視圖或處理特定的業務邏輯。如果你顯示設置第三個參數中silent為true,將不會觸發“change”事件。

p1.set({name: 'Backus', age: 87}, {silent: true})

 

從set源碼可以看到,this._validate執行在前,this.trigger在后。也就是說如果驗證失敗,那么就不會執行change事件。

 

附set方法執行流程圖

 

把模型保存到服務器 - save

save方法會把模型保存到服務器端,它的參數和set完全一致。內部調用set和sync方法。

以下幾點需要注意

1. 默認會進行屬性校驗,即options.validate為true,校驗失敗將不會請求后台程序,也不會設置模型的this.attributes,直接返回,見源碼

if (attrs && !options.wait) {
  if (!this.set(attrs, options)) return false;
} else {
  if (!this._validate(attrs, options)) return false;
}

2. 首次保存時(isNew),會采用create方式(HTTP post),已存在的model則只需要update方式(HTTP put)

如下

var p1 = new Person()
p1.save({name: 'Backus', age: 87}) // create
p1.save({name: 'John'}) // update

3. 可以傳success和error兩個回調函數以處理保存成功與失敗場景

var p1 = new Person()
p1.save({name: 'Backus', age: 87}, {
    success: function() {},
    error: function() {}
})

4. 事件,save成功后會依次觸發模型的“change”、“request”、“sync”事件。如果監聽了這些事件,那么回調將得到執行

 

從服務器獲取模型 - fetch

從服務器端獲取使用fetch方法,fetch方法很短

fetch: function(options) {
  options = options ? _.clone(options) : {};
  if (options.parse === void 0) options.parse = true;
  var model = this;
  var success = options.success;
  options.success = function(resp) {
    if (!model.set(model.parse(resp, options), options)) return false;
    if (success) success(model, resp, options);
    model.trigger('sync', model, resp, options);
  };
  wrapError(this, options);
  return this.sync('read', this, options);
},

1. 它使用read方式(HTTP get)

2. 請求成功后調用set方法設置模型屬性(this.attributes),設置失敗則直接返回不調用success,設置成功接着調用success,最后派發“sync”事件

 

模型的事件 - change/invalid/sync

上面已經提到的事件 change、 invalid、sync。change事件還可以只監聽指定的屬性,格式:"change:" + attributeName。如下

var p1 = new Person()
p1.on('change:name', function(model, error) {
    console.log('name has changed')
})

控制台中分別設置下name和age

可以看到,只有設置name時才觸發事件。

 

除了Backbone.Model自身提供的事件,你還可以給自己的Model添加自定義的事件以滿足需求。

 

鳥瞰圖

1. 內部狀態,各屬性影響的方法

 

2. 構造器執行流程

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM