您的位置:首页 > 其它

Backbone.Model

2016-02-06 14:43 405 查看

Backbone.Model概论

一个Backbone 模型可以比作一张表单结构,头部类似表单的列,数据类似表单的行。Backbone.Model对象定义列标签,再用预定义和自定义的方法包裹每一行里的 数据(即属性),以便进行数据转换、验证和访问控制。由Backbone.Model创建模型实例或者一个继承的Backbone.Model,提供对象 到实际数据的存储。

你可以把一个Backbone.Model构造函数比作表单的列标题,其方法和属性通用于每一行的数据。由构造函数创建的一个实例,用实际数据填充上面的表格。

//i.e.
new Backbone.Model(
{firstName:"John",lastName:"Doe",phone:"1-111-1111"}
);

请注意,Backbone.Model为每一行数据提供属性和方法(例如:get("phone")),也支持定义你自己的方法和属性(例如:getFullName())。

以上提到的内容只是Backbone模型的部分特性。在Backbone里,还有一部分内容涉及在HTTP上通过restful JSON api使用AJAX来同步数据。在本文中,我们将不讨论关于同步的细节。本小节主要讨论的是一个模型(以及模型的集合)的生命周期,但不包括同步数据这一 块。

子类与创建一个Backbone.Model

要创建一个通用数据模型,我们只需要从Backbone.Model实例化一个实例,再传入模型将储存的值(也就是Backbone属性)。例如,下面我创建了两个联系模型,一个是JohnDoe,另一个是JaneDoe。

var contact1Model = new Backbone.Model(
{firstName:"John",lastName:"Doe",phone:"111-111-1111"}
);
 
var contact2Model = new Backbone.Model(
{firstName:"Jane",lastName:"Doe",phone:"222-222-2222"}
);

然而,更倾向于先继承/分类基础Backbone.Model,再实例化一个实例,这样你就可以添加自己域特定的属性。

在下面代码的中,我继承了Backbone.Model构造函数,创建出一个子构造函数(ContactModel),并定义getFullName()方法,于是所有创建于ContactModel的模型都将继承getFullName()方法。

var ContactModel = Backbone.Model.extend({ //extend Backbone.Model
getFullName:function(){
return this.get("firstName") +" "+ this.get("lastName");
}
});
 
var contact1Model = new ContactModel( //instantiate ContactModel instance
{firstName:"John",lastName:"Doe",phone:"111-111-1111"}
);
 
var contact2Model = new ContactModel( //instantiate ContactModel instance
{firstName:"Jane",lastName:"Doe",phone:"222-222-2222"}
);
 
//在我们的模型上调用getFullName方法
console.log(contact1Model.getFullName()); //logs John Doe
console.log(contact2Model.getFullName()); //logs Jane Doe

提示:

当实例化一个模型时,一组数据可以被传入到一个对象的位置。在这之后Backbone将转移这个数组到一个对象,通过给予传递值(["foo","bar"])数值的属性名称,成为了({"1":"foo","2","bar"})。

实例化模型传递的第二个参数是一个选项对象,包含了collection, url, urlRoot和parse选项。其中大部分将在下一篇文章中加以详述,因为它们涉及到同步数据。

别忘了initialize函数,在继承模型时设置的,用于放置创建模型实例需要运行的逻辑关系。尤其需要注意的是,初始化函数中的this值是所创建的模型实例的作用域。

一种方便的clone()方法在模型实例上可用,将返回一个新的模型实例附带一份clone()方法调用的数据副本。这是从模型实例上创建模型的一种便捷方式。

Backbone.Model方法、属性与事件

Backbone模型实例包含以下方法和属性

get
set
escape
has
unset
clear
id
idAttribute
cid
attributes
changed
defaults
toJSON
sync
fetch
save
destroy
Underscore Methods:(keys、values、pairs、invert、pick、omit)
validate
validationError
isValid
url
urlRoot
parse
clone
isNew
hasChanged
changedAttributes
previous
previousAttributes
粗体所显示的方法或属性不会在本文章中叙述,在以后的文章中我们会讨论到这些与同步相关的方法或属性。

此外,模型还可以使用以下嵌入事件:





设定模型的默认值/属性

在继承一个模型时,你可以设定一系列默认值共享给所有实例。在下面的代码中,我设置了一个默认值给firstName和lastName。

var ContactModel = Backbone.Model.extend({ //继承Backbone.Model
defaults: {
firstName : "no first name yet",
lastName : "no last name yet"
}
});
 
var contact1Model = new ContactModel( //实例化模型实例
{firstName:"John"}
);
// firstName设置为John,同时保持lastname为默认值不变
console.log(contact1Model.get("firstName")); //日志 John
console.log(contact1Model.get("lastName")); //日志"no last name yet"

如果你想让实例不引用同一个默认对象,你可以提供一个默认函数值,将会创造出特殊的默认值(不引用同一个默认对象)。

var ContactModel = Backbone.Model.extend({ //继承Backbone.Model
defaults: function(){
this.firstName = "no first name yet";
this.lastName = "no last name yet";
return this;
}
});
 
var contact1Model = new ContactModel( //实例化模型实例
{firstName:"John"}
);
// firstName设置为John,同时保持lastname默认值不变
console.log(contact1Model.get("firstName")); //日志 John
console.log(contact1Model.get("lastName")); //日志 "no last name yet"

在上面代码中,每一个实例各将会使用一个特殊默认对象,而不是每一个实例引用同一个默认对象。

模型数据的设置、更改、获取、复原与删除

Backbone提供一组通用的方法(set(), has(), get(), unset(), clear())来处理模型数据。下面我将演示每一种方法。

var contact = new Backbone.Model(); //实例化模型实例
//设置/编辑数据
contact.set({firstName:"John",lastname:"Doe",phone:"1-111-1111"});
//拥有firstName属性,注意,无论属性值为何都将返回true
console.log(contact.has("firstName")); //日志 true
//获取数据
console.log(contact.get("firstName")); //日志 John
//复原数据
contact.unset("lastname");
//验证数据已被复原
console.log(contact.has("lastName")); //日志 false
//清除所有数据
contact.clear();
//验证数据已被清除
console.log(contact.attributes); //日志 empty {}

提示:

这些方法应当被用来替代直接编辑内部attributes对象,以便模型中的事件能够被正确的触发。
set(), unset()和clear()方法能够调用内部change事件。
set()方法接收一个选项对象(例如:set({"name":"value","name":"value"}))或两个字符串参数(例如:set("name","value"))。

set(), unset()和clear()方法都接收{silent: true}选项,阻止任意Backbone嵌入事件发生。

在设置值之前,{validate:true}选项和set()方法能够一起用来验证这些值(例如:set({"foo":"foo"},{validate:true}))。

访问一个模型数据/属性

Backbone提供attributes属性,能够直接访问包含一个模型数据的内部对象。

var contact1Model = new Backbone.Model( //instantiate model instance
{firstName:"John",lastName:"Doe"}
);
 
console.log(contact1Model.attributes); //日志 {firstName="John", lastName="Doe"}

Backbone提供直接访问到这个对象,一般情况下该对象不会被直接操纵。事实上,也不要这样做。如果你想编辑模型数据,可以使用set(), get(), unset(), clear()或者复制(model.toJSON();)attributes对象,编辑副本之后再利用set()更新模型。

提示:

直接操纵attributes属性将不会调用内部模型事件。

利用toJSON()获取模型数据/属性的一个副本

toJSON()模型方法返回attributes内部数据对象的一个副本。

var contact1Model = new Backbone.Model( //实例化模型实例
{firstName:"John",lastName:"Doe"}
);
 
console.log(contact1Model.toJSON()); //日志 {firstName="John", lastName="Doe"}
 
//请注意,这不是一个引用,而是属性对象的一个副本
//i.e.
console.log(contact1Model.toJSON === contact1Model.attributes); //日志 false

当你需要获取一个对象的干净的副本作为一个模板时,这种方法非常方便。

提示:

使用toJSON()方法可以获取属性对象的一个浅表克隆(
_.clone),任意嵌套对象或数组将从原型引用,而不是复制。 
传递一个模型实例到JSON.stringify,将内部使用Backbone的toJSON()方法。

过滤模型数据

Backbone从underscore.js库代理6种方法(keys(), values(), pairs(), invert(), pick(), omit()),都可以直接用在模型数据上。这些函数可以为过滤所需模型数据状态提供帮助。下面我将展示最常用的4种方法。

var contact = new Backbone.Model({
firstName:"John",lastName:"Doe",phone:"1-111-1111"
});
 
//返回数据的数组/属性键
console.log(contact.keys()); //日志 ["firstName", "lastName", "phone"]
 
//返回数据的数组/属性值
console.log(contact.values()); //日志 ["John", "Doe", "1-111-1111"]
 
//复制数据/属性对象,返回包含选中键的对象
console.log(contact.pick("phone")); //日志 {phone="1-111-1111"}
 
//复制数据/属性对象,返回不包含选中键的对象
console.log(contact.omit("firstName","lastName")); // 日志 {phone="1-111-1111"}

监听模型change事件

当模型中的数据发生变化时,change事件会同时被广播,通常情况下一个视图能够监听此类事件。

在下面的代码中,模型创建之后,又创建了一个视图来监听模型上的change事件。模型数据的任何改变都将触发一个change事件,理想情况下,还会有一个重新渲染。

var contact= new Backbone.Model();
 
var ContactView = Backbone.View.extend({
initialize:function(){
this.listenTo(contact,"change",this.render); //listen to change event on model
},
render:function(){
console.log("data changed, re-render");
}
});
 
new ContactView();
 
contact.set({ //这将触发change事件
firstName:"john",lastName:"Doe",phone:"111-111-1111"
});
 
contact.unset("phone"); //这将触发change事件

还可以只监听模型上一个特殊属性的变化,需要将属性名称和change事件指定给一个监听者("change:[ATTRIBUTE]")。比如,下面我将在原来的代码上加以变化,只对联系模型上的firstName属性改变加以监听。

var contact= new Backbone.Model();
 
var ContactView = Backbone.View.extend({
initialize:function(){
//监听模型上的change事件
this.listenTo(contact,"change:firstName",this.render);
},
render:function(){console.log("render a change, data changed");}
});
 
new ContactView();
//change事件被激活,因为我们只监听firstName
contact.set("firstName","john");
contact.set("phone","222-222-2222"); //no change event trigger

利用hasChanged()和changedAttributes()验证一个模型已变化与变化的内容

hasChanged()和changedAttributes()模型方法能够验证在最后一个change事件之后变化是否已生效,并且验证具体是什么发生了变化。

在下面代码中,我设置了一个联系模型,然后立即改变电话号码属性。

//创建联系模型,用数据实例化模型时并没有change事件被激活
var contact=new Backbone.Model({firstName:"John",lastName:"Doe",phone:"1-111-1111"});
 
//做出一个改变
contact.set({phone:"2-222-2222"});
 
//验证一个变化已经发生
console.log(contact.hasChanged()); //logs true
 
//获取已改变的属性
console.log(contact.changedAttributes()); //logs {phone="2-222-2222"}
console.log(contact.changed); //obj{phone="2-222-2222"}

console.log(contact.changed.phone); //"2-222-2222"

代码中,通过改变电话号码,内部change事件被立即调用了,hasChanged()方法返回一个布尔函数表示模型已经发生了改变。为了得到包含该属性的发生改变的一个对象,需要在模型上调用changedAttibutes()方法。

利用previous()与previousAttributes()获取原始属性值

previous()和previousAttributes()方法能够用来获取change事件之前的一个属性值。在下面的代码中,我设置了一个联系模型,更改了phone和firstName属性,然后利用previous()和previousAttributes()方法检索号码属性的前值,以及最后change事件之前的所有模型属性状态。

//创建联系模型,用数据实例化模型时没有change事件被激活
var contact=new Backbone.Model({firstName:"John",lastName:"Doe",phone:"111-111-1111"});
 
//做出一个改变
contact.set({phone:"2-222-2222",firstName:"Jane"});
 
//获取电话号码的初始值
console.log(contact.previous("phone")); //日志 111-111-1111
 
//获取最后change事件之前的所有属性状态
console.log(contact.previousAttributes()); //日志 {firstName:"John",lastName:"Doe",phone:"1

在模型设置或存储之前验证模型数据

当设置或存储模型数据(在下一篇文章中将讨论存储)之前,一个验证函数将被调用来验证数据质量。

默认情况下,validate属性还未定义。在模型上为了定义一个验证函数,可以传递validate:function(attributes,options){}到extend(),或者直接更新模型实例上的validate属性。一个验证错误跳闸,就是简单的从一个接收false的函数返回任意值。

在下面的代码中,我为电话号码设置了一个验证函数,确保任意无效的电话号码将不会被set()。

var contact = new Backbone.Model({
firstName:"John",lastName:"Doe",phone:0
});
 
contact.validate = function(attributes,options){
var validPhone = /\(?\d{3}\W?\s?\d{3}\W?\d{4}/.test(attributes.phone);
if(!validPhone){
返回"Setting or Saving Invalid Phone Number Attempted";
}
}
 
contact.set("phone","111-111-1111",{validate:true}); //set
contact.set("phone","111-1-1111",{validate:true}); //不会set,验证失败
 
console.log(contact.get("phone")); //没有无效的电话号码
console.log(contact.validationError); //读取最后一个验证错误

从验证函数最后一个返回的值如果不是false,则可以引用模型validationError属性。代码中我们从验证函数返回一个无效的信息,并访问validationError属性,后台输出这个信息。

提示:

一个validate回调函数将所有模型属性作为第一个参数传递,第二个参数包含set()或save()选项对象可以验证跳闸。

验证只发生在使用save()、set()方法,与validation:true选项,或者利用isValid()进行手动验证。

监听一个模型的invalid事件

当一个模型的validate函数失败,嵌入invalid事件将被广播。在下面的代码中,我演示了监听这个事件并输出参数传递给无效的回调函数。

var contact = new Backbone.Model({firstName:"John",lastName:"Doe"});
 
contact.validate = function(attributes,options){
var validPhone = /\(?\d{3}\W?\s?\d{3}\W?\d{4}/.test(attributes.phone);
if(!validPhone){返回"Setting or Saving Invalid Phone Number Attempted";}
};
 
//Backbone在联系模型上监听无效事件
Backbone.listenTo(contact,"invalid",function(model,error,options){
console.log(model,error,options);
});
 
//设置无效电话号码触发无效事件
contact.set("phone","111-1-1111",{validate:true}); //不会set,验证失败

在模型上手动运行validate 

validate函数能够通过调用isValid()方法被手动调用。在下面的代码中,validate函数在继承Backbone.model构造函数时被设置,因此所有模型实例都能使用这个验证函数。在创建模型实例过程中,为了保证数据都被验证了,我在调用initialize时将运行validate函数,来获取通过了的无效数据。

var ContactModel = Backbone.Model.extend({ //extend Backbone.Model
validate :function(attributes,options){
var phone = /\(?\d{3}\W?\s?\d{3}\W?\d{4}/.test(attributes.phone);
var firstName = /^[A-Z]"?[a-zA-Z]+(-[a-zA-Z]+)?$/.test(attributes.firstName);
var lastName = /^[A-Z]"?[a-zA-Z]+(-[a-zA-Z]+)?$/.test(attributes.lastName);
if(!phone !firstName !lastName){
return "Setting, Saving, Or Seeding Invalid Data"
}
},
initialize:function(){
//运行验证, 如果无效将输出信息
if(!this.isValid()){console.log(this.validationError)}
}
});
var contact1Model = new ContactModel({ //validate seeded data
firstName:"jo234 hn",lastName:"ao321-- e",phone:"111-1111-111111"
});

请注意,isValid()方法返回一个有用的布尔函数,显示模式是否有效。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: