Backbine.js实战第四章----数据模型

    Model在Backbone中为数据模型,是一个最基础、最基本的数据基类,用于原始数据、底层方法的封装和定义。它的结构类似于关系数据库中的映射对象,可以装在数据库中的记录信息,并通过自定义的方法完成数据的操作之后,将数据同步到服务器中。正确理解和掌握Model的概念和使用方法,是熟悉使用Backbone框架开发的一项重要标志。


4.1 创建数据模型

   在Backbone中,创建数据模型的方法十分简单,只要通过Model.extend()方法就可以定义一个数据模型。在定义模型的过程中,还可以初始化数据、定义构造方法,当一个数据模型创建完成后,可以通过实例化的方式,产生一个个数据模型对象。 这些模型对象都继承了数据模型中的初始化数据,并且可以很方便地调用创建时设置的方法。接下来逐一进行介绍。


4.1.1 创建一个简单模型对象

    当使用Model.extend()方法构建数据模型之后,就可以通过实例化的方式创建一个模型对象,模型对象将自动继承模型中定义的属性和方法。

    示例4-1  创建一个简单模型对象

 1.功能描述

    在构建模型对象时,首先添加initialize函数,在该函数中,通过一个名为"intNum"的变量累计执行函数的次数,并将该次数显示在浏览器的控制台中。然后,实例化两个模型对象,在实例化过程中,将自动执行initialize函数,观察浏览器控制台输出内容的变化。

var student = Backbone.Model.extend({
	initialize:function(){
		intNum++;
		console.log("您构建了"+intNum+"个对象");
	}
});
var intNum = 0;
var stuA = new student();
var stuB = new student();


   在上述代码中,使用extend方法构建了一个数据模型student,通过initialize属性定义了一个当数据模型被实例化时执行的函数,即构造函数,它的功能是通过变量intNum记录构造函数执行的次数,并将结果输出到浏览器的控制台中。接下来,定义并初始化变量intNum,并以实例化的方式定义两个模型对象,分别为stuA和stuB。从上图中可以看出,每当实例化一个模型对象时,都会调用构造函数,因此记录构造函数执行次数变量intNum将会自动累加。本实例中两次实例化模型对象,因此执行了两次构造函数。


4.1.2 对象模型赋值的方法

    对于一个数据模型来说,赋值的方法是在定义时通过defaults属性设置数据模型的默认值,而对于一个已经实例化的模型对象来说,赋值的方法是通过调用对象的set方法,重置模型中的默认值。set方法有两种形式。

    第一种是单个设置,代码如下所示。

Obj.set(attrName,attrValue);

    其中,参数attrName表示属性名称,attrValue表示对应的属性值。调用上述方式一次只能设置一个属性值。

    第二种形式为批量设置属性值,代码如下所示。

Obj.set({attrName1:attrValue1,attrName2:attrValue2,...});

    其中,通过{...}方式可以设置多个属性值,属性名称与对应值之间使用冒号(:)隔开,而属性与属性之间,则使用逗号(,)隔开。

    无论使用set方法的何种形式赋值,当完成对象赋值操作之后,就可以通过调用对象的get或escape方法获取已设置的对象属性值,其调用格式如下。

Obj.get(attrName);

Obj.escape(attrName);

    其中,参数attrName表示需要获取的属性名称,而get与escape方法虽然都可以获取对象的属性值。但两者间的区别在于escape方法不仅获取对象的属性值,而且能将属性值中包含HTML代码的部分进行实体化,即变成一个统一的字符串实体,这样可以有效避免代码被攻击,确保取值的安全。接下来通过一个简单的示例来演示对象赋值和取值的过程。


    示例4-2  对象模型赋值的方法

1.功能描述

    在构建模型类时,首先添加defaults属性设置模型对象的属性名称,然后实例化一个名为“stuA”的模型对象,并调用对象的set方法重置属性值,最后在浏览器的控制台中输出这些重置后的属性值内容。

var student = Backbone.Model.extend({
	initialize:function(){
		//执行构造代码
	},
	defaults:{
		Code:"",
		Name:"",
		Score:""
	}
});
var stuA = new student();
stuA.set({
	code:"10101",
	Name:"'皮卡丘'",
	Score:"300",
	Class:"一年级<二>班"
});
console.log(stuA.get("Name")+"在"+stuA.get("Class")+"读小学");
console.log(stuA.escape("Name")+"在"+stuA.escape("Class")+"读小学");


2.源码分析

    在上述代码中,当构建student数据模型时,通过defaults属性设置了模型的3个默认属性,并将它们的属性值设为空,以方便实例化对象时重置属性值。当实例化一个模型对象stuA之后,通过调用对象的set方法,重置模型中3个默认属性值,并添加一个Class属性,同时设置属性值。最后在浏览器的控制台中调用对象的get和escape两种方法输出对象的指定属性值。

    从上图中可以看出,在构建对象模型时,不仅可以通过defaults属性设置默认属性并赋值,还可以调用对象的set方法赋值的时候自定义属性,如本例的Class属性;另外,使用get和escape方法获取属性值时,前者原样获取,后者会将属性值中包含的HTML特殊字符进行编码处理后再返回,如将示例中的单引号处理成“&#x27”等。


4.1.3 自定义模型中的方法

    在构建对象模型时,不仅可以设置模型对象的默认属性,而且还可以自定义模型对象的方法。众所周知,与设置属性相比,自定义模型对象的方法通常需要实现一些相应的功能,在方法中可以使用this对象访问模型对象本身。

    示例4-3  自定义PrintLog方法

1.功能描述

    在示例4-2代码的基础上,自定义一个名称为PrintLog的方法,然后实例化一个模型对象之后。通过对象调用该方法,在浏览器的控制台输出对象重置后的属性内容。

var student = Backbone.Model.extend({
	initialize:function(){
		
	},
	defaults:{
		
	},
	PrintLog:function(){
		console.log(this.get("Name")+"在"+this.get("Class")+"读小学");
		console.log(this.escape("Name")+"在"+this.escape("Class")+"读小学");
	}
});
var stuA = new student();
stuA.set({
	Code:"10102",
	Name:"皮卡丘",
	Score:"300",
	Class:"一年级<一>班"
});
stuA.PrintLog();


2.源码分析

    在上述代码中,当构建数据模型student时,以函数的方式自定义一个名为PrintLog的方法,该方法的功能是在浏览器的控制台中输出树勇get和escape方法获取的对象属性值。当实例化一个模型对象stuA,并使用set方法添加并重置对象属性之后,就可以像调用对象自带方法一样,调用自定义的PrintLog方法。

    从图中可以看出,采用调用对象的方式实现的效果与执行输出代码是完全一样的,但调用对象方法的形式使代码更简洁、通用性好、可维护性更加。另外,需要说明的是,在自定义方法时,代码this.get("Name")中的this表示对象本身,当没有重置对象的属性值,它将获取构建模型时设置的默认属性值,否则获取重置后的对象属性值。


4.1.4 监听对象属性变化

    在第3章介绍事件API时,演示过调用on方法绑定对象的属性事件,其实也可以在构建数据模型时,使用on方法去绑定对象的属性事件,监听属性值的变化而绑定的过程代码,通常放在数据模型构造函数initialize中,这样,当实例化某个数据模型对象时,就自动绑定了对象的事件,一旦触发了事件,便可以执行相应的代码。

    示例4-4  监听Name属性值的变化

1.功能描述

    在示例4-3的基础上,向数据模型构造函数initialize中绑定对象的一个属性事件,监听Name属性值的变化。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("change:Name",function(){//这里可以不写model,value参数
			var oldName = this.previous("Name");
			var newName = this.get("Name");
			if(oldName!=newName){
				console.log("Name原值:"+oldName+",新值:"+newName);
			}
		});
	},
	defaults:{
		Code:"",
		Name:"皮卡丘",
		Score:""	
	}
});
var stuA = new student();
stuA.set("Name","杰尼龟");

2.源码分析

    在上述代码中,当构建数据模型时添加了构造函数initialize,在这个函数中使用on方法绑定对象属性事件change:Name。在该事件执行的自定义函数中,分别用oldName和newName两个变量保存上一次和修改后的Name属性值,如果这两个值发生变化,在浏览器的控制台中输出Name属性的原值和新值内容。

    接下来,实例化一个模型数据对象stuA,并调用该对象的set方法重置了Name属性值,这一操作将触发已绑定的change:Name属性事件,并执行事件的自定义函数。

    从上图中可以看出,在构造函数中,同样可以调用对象的on方法绑定各类事件,监听事件的触发。由于在本示例中,对象的Name属性默认值为“皮卡丘”,而调用set方法重置为“杰尼龟”。当触发change:Name事件时,Name属性值已经发生了变化,所以在浏览器控制台输出获取的Name属性的原值和新值。

    需要说明的是,构造函数this.on中的this表示实例化后的对象本身,而this.previous中的this虽然也表示对象本身,但如果构造函数中带有model和value两个属性事件特有的参数,则 this可以被取代,即下面两行代码是等价的。

    var oldName = this.previous("Name");

    var newName = this.get("Name");

等价于:

    var oldName = model.previous("Name");

    var newName = value;


4.2 模型对象操作

     构建一个数据模型类之后,接下来的任务就是针对模型实例化对象,并对实例化后的对象进行一系列的数据操作,如读取、(重置)修改、验证、删除对象中数据。接下来逐一介绍这些操作实现的方法和技巧。

4.2.1 读取数据

    前面章节介绍过,如果要读取一个模型对象中的数据,通常调用对象的get和escape方法,前者是直接返回对象中的数据,后者则是返回经过对象中某些特殊字符进行编码处理后的数据。接下来分别对这两种方法进行介绍。

    示例4-5  调用get方法获取对象指定的属性值

1.功能描述

    首先构建一个模型类,设置默认的属性名称,然后实例化一个名为“stuA”的模型对象,最后在浏览器的控制台中输出使用get方法获取的对象属性值。

var student = Backbone.Model.extend({
	defaults:{
		Code:"",
		Name:"",
		Score:""	
	}
});
var stuA = new student({
	Code:"10103",
	Name:"皮卡丘",
	Socre:""
});
console.log("学号:"+stuA.get("Code"));
console.log("姓名:"+stuA.get("Name"));
console.log("性别:"+stuA.get("Sex"));
console.log("分数:"+stuA.get("Score"));

2.源码分析

    在上述代码中,首先构建了一个数据模型student,在该模型中,通过defaults属性设置对象的一些默认属性值。然后,实例化一个模型对象stuA,在实例化过程中,重置对象的3个属性值。最后调用get方法获取对象指定的属性值,并将这些值输出在浏览器的控制台中。

    从上图中可以看出,当使用对象的get方法读取数据时,会自动与上一次的值进行比较。如果没有发生变化,返回上一次的对象数据;否则,获取变化后最新的对象数据。如果不存在该项数据名称,则返回undefined值。


4.2.2 修改数据

     完成一个数据模型的构建之后,就可以通过实例化的对象修改模型类中的默认属性值。常用方法有两种:一种是在实例化对象的同时修改默认的属性值,另一种是调用对象的set方法针对一个或多个属性进行重置。当数据修改后,如果不与上一次的值相同,可以调用对象的get或escape方法进行获取。

    示例4-6 调用set方法批量重置默认属性值

1.功能描述

    首先构建一个模型类,并设置默认的属性名称。然后,分别实例化stuA和stuB两个模型对象。在实例化过程中,对象stuA在实例化时,直接给默认的属性名赋值,而对象stuB则通过set方法,在对象实例化后批量赋值。最后,在浏览器控制台中输出两个对象的属性值。

var student = Backbone.Model.extend({
	defaults:{
		Code:"",
		Name:"",
		Score:""	
	}
});
var stuA = new student({
	Code:"10104",
	Name:"皮卡丘",
	Score:"500"
});
var stuB = new student();
stuB.set({
	Code:"10105",
	Name:"杰尼龟",
	Score:"300"
});
console.log("1.学号:"+stuA.get("Code")+
			"  姓名:"+stuA.get("Name")+
			"  分数:"+stuA.get("Score"));
console.log("2.学号:"+stuB.get("Code")+
			"  姓名:"+stuB.get("Name")+
			"  分数:"+stuB.get("Score"));

2.源码分析

    在上述代码中,分别实例化两个模型对象stuA和stuB。前者是在实例化时便修改了对象模型的默认属性值,后者则是在实例化对象之后,使用set方法批量重置对象模型中的默认属性值。最后调用对象的get方法获取对象数据,并输出至浏览器的控制台中。

    从上图中可以看出,无论是使用实例化对象的同时修改属性值,还是实例化之后使用set方法重置对象的属性值,都可以调用get方法获取。


4.2.3 开启数据验证

    Backbone中提供了一套完整的数据验证机制,用于确保写入数据模型中数据的正确性,尤其是在最新的1.0.0版本,改变了之前的自动验证方式,改为设置验证方式。接下来详细介绍Backbone .1.0.0中,数据验证实现的方法。

    要实现对数据中某个属性值的验证,需要完成一下3个步骤的操作。

    (1)添加validate方法。在该方法中确定数据校验的标准,即数据在什么情况下,认为它是不正确的,如果不正确,返回提示信息。

    (2)绑定对象validate事件。 数据验证失败后会触发该事件,在该事件中,通过返回的参数可以接收validate方法中传来的提示信息。

    (3)使用set方法添加/修改属性时,必须将validate属性设置为true,用于通知Backbone框架此次的数据操作是需要进行验证的。

    通过上述步骤的操作,就可以开启对某项数据的验证,下面通过一个简单的示例来说明数据验证的过程。

    示例4-7 开启数据验证

1.功能描述

    在构建模型类时,首先添加validate方法,在该方法中对属性中的“姓名”和“分数”做有效性验证。然后,通过set方法重置属性值,并将validate的值设为true。更新一个不符合验证规则的属性值时,在浏览器的控制台中以JSON形式输出原有对象属性值内容。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必须是字符!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分数必须是数字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"validate":true});
console.log(stuE.toJSON());

2.源码分析

    在上述代码中,构建数据模型类,在构造函数中绑定对象的inalid事件。在该事件中,将在浏览器的控制台输出验证错误提示信息。其次,在数据模型类中,添加validate方法,设置了Name、Score两个属性的验证规则。最后,在调用实例化对象stuE的set方法时,将validate属性值设置为true。

    由于在调用实例化对象stuE的set方法时,将Name属性的值重置为12345,这是一个数字类型,这样的设置不符合“Name属性必须为字符”的规则。由于开启了验证,将调用validate方法的规则进行对应数据的验证。验证失败后,触发已绑定invalid事件,接收传回的错误提示信息,并将该信息输出至浏览器的控制台中。

    另外,在调用validate方法进行数据验证时,将会逐一对规则进行过滤。如果验证失败,会终止整个set方法的操作,直接执行invalid事件中的代码。也就是说,本示例中由于Name属性没有通过验证,即使Score属性设置了正确的值,也不会进行更新。因为整个操作都已停止,通过最后一行代码输出对象stuE的全部数据可以看出,stuE对象中的各属性值仍然是初始化的值,没有发生变化。

    
4.2.4 关闭数据验证

    在Backbone中调用set方法时,不将validate属性值设置为true,本次set方法将不会进行数据验证。此外,在调用set方法时,还可以将silent属性值设置为true,表示静默式修改数据,即在修改数据时,不触发任何事件。这其中也包括绑定的属性事件,当然也不会触发数据验证事件,而是直接更新数据。

    示例4-8 关闭数据验证

1.功能描述

    在示例4-7基础之上进行修改,只在使用set方法重置属性值时,将silent属性值设置为true,不设置validate,其余代码不变。最后,将重置后的对象属性值内容以JSON格式的形式输出至浏览器的控制台中。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
		this.on("chaneg:Name",function(model,value){
			console.log("您触发了Name属性修改事件!");
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必须是字符!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分数必须是数字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"silent":true});
console.log(stuE.toJSON());
2.源码分析

    上述代码在示例4-7基础添加了一个对象的change:Name事件。在调用对象set方法时,将Name和Score的属性值分别设置为数字和字符类型,以触发验证的事件,同时将silent属性值设置true。最后,在浏览器的控制台中输出整个stuE对象的属性值。

   由于在set方法中将silent属性值设置true,表示将关闭所有触发的事件,采用静默方式进行更新,因此,即使设置的属性值不符合验证规则,validate方法也不会被触发,而是直接重置对象的属性值。在属性值被重置的过程中,虽然已绑定change:Name事件,但由于是静默方式更新,该事件同样也不会被触发。最终在浏览器的控制台中输出更新后的数据。

4.2.5 更新数据回滚

    在Backbone中调用set方法时,可以将silent属性值设置为true,采用静默方式更新数据。但为了确保数据的安全性,可以针对已更新的数据进行二次验证,如果不符合验证规则,可以调用对象的previous方法进行上一次数据的回滚。

    示例4-9 更新数据回滚

1.功能描述

    在示例4-8基础之上进行修改,关闭数据验证后,对已经重置的对象属性值进行手动验证,以确定其数据的有效性。如果手动验证不成功,将用previouse方法获取的数据回滚值重置为对象的属性值。最后,在浏览器的控制台以JSON形式输出对象的属性内容。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
		this.on("chaneg:Name",function(model,value){
			console.log("您触发了Name属性修改事件!");
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必须是字符!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分数必须是数字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"silent":true});
console.log(stuE.toJSON());
if(!_.isString(stuE.get("Name"))||!_.isNumber(stuE.get("Score"))){
	stuE.set({
		"Name":stuE.previous("Name"),
		"Score":stuE.previous("Score")
	});
}
console.log(stuE.toJSON());

2.源码分析

    在上述代码中,调用对象stuE的get方法获取属性当前最新的值,然后进行二次验证。如果没有通过验证,再次调用对象set方法,将使用previous方法获取的上一次数据更新为对象的最新值,实现对象数据的回滚。

    虽然在第一次调用set方法时启用静默方式,更新两个不符合验证规则的属性值,但通过数据的二次验证,调用previous方法获取第一次set方法更新之前的数据,并再次调用set方法将获取的数据进行更新,实现异常数据的回滚。

    上图中虽然都是输出对象stuE的JSON格式值,但两次输出的内容却不同,第一次输出的是采用静默方式更新后的值,第二次输出的是数据回滚之后对象stuE的属性值。


4.2.6 删除数据

    在Backbone中,可以调用对象的unset和clear方法删除模型对象中的数据,前者是删除指定属性名称的数据,调用格式如下。

Obj.unset(attrName);

    后者为清除对象中的全部数据,该方法没有参数,调用的格式如下。

Obj.clear();

    接下来通过简单的示例介绍使用unset和clear方法删除模型中对象数据的过程。

    示例4-10 调用unset方法删除指定属性的数据

1.功能描述

    首先构建一个模型类,实例化一个名为“strE”的类对象。然后,调用set方法重置对象的属性值。最后,分别调用unset和clear方法删除指定的某个和全部的属性数据,在删除过程中,分别在浏览器的控制台中输出数据删除后的对象属性值。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
//删除name属性
stuE.unset("Name");
console.log(stuE.get("Name"));
console.log(stuE.toJSON());
stuE.set("Name",stuE.previous("Name"));
console.log(stuE.toJSON());
//清除全部数据
stuE.clear();
console.log(stuE.toJSON());


2.源码分析

    在上述代码中,首先调用stuE对象的set方法更新一次数据,同时调用对象的unset方法删除Name属性的数据,并输出删除数据后,Name属性值和整个stuE对象的JSON格式内容。然后第二次调用set方法,将Name属性回滚后的值更新为当前最新属性值,并再次输出整个stuE对象的JSON格式内容。最后,调用对象的clear方法清空stuE对象的全部数据,并再次以JSON格式输出对象的内容。

    当删除stuE对象的Name属性数据之后,再次调用该属性值时,将返回undefined,表示对应属性已经不存在;同时,以JSON格式输出整个stuE对象时,Name属性同样不存在。通过这点可以看出,使用unset方法不仅是删除属性的数据,而且该属性也一并删除,这是因为当模型对象执行unset方法时,模型内部将调用delete关键字将Name属性从对象中移除,从而实现删除数据的功能。

    由于unset方法也是数据更新方法的一种,也能调用previous方法对已删除的数据进行回滚。因此,在本示例中,当调用previous方法获取回滚后的Name属性值,并将该值使用set方法重置为Name属性的新值后,再次以JSON格式输出整个stuE对象时,已删除的数据又重新返回,如上图中第三行所示。

    调用stuE对象的clear方法清空整个对象的数据之后,全部的数据都将被删除,包括对象的属性和属性值。因此,最后一次以JSON格式输出整个stuE对象时,该对象的内容是一个空值,如上图中第四行所示。



4.3 对象属性操作

    在Backbone中,每一个实例化后的模型对象都包含一个或多个属性,可以通过调用对象的set方法设置这些属性的值,并调用对象的get方法返回指定属性名称的值。用户对模型对象的数据操作,在本质上来说,就是对一个个对象属性的操作。本章将进一步介绍操作对象属性的原理和获取属性修改前数据的方法。

4.3.1 attributes对象

    在Backbone中,实例化后的模型对象所有属性都保存在一个名为attributes的对象中,对象的set或get方法都是围绕该对象进行存取的。使用set方法设置对象属性值时,该方法内部执行了一个兼容。即第一个参数ket是对象时,直接将该对象复制到attributes中;如果是字符串形式,则在内部将key和value转成一个临时的对象attrs,再把它赋值到attributes中,这样可以使set方法支持单个属性值和多个属性值的设置。

    除使用get方法获取对象指定的属性值外,还可以直接调用对象attribute的方法获取全部的属性值。获取的方式有两种:一种是直接输出attributes对象,另一种是遍历attributes对象,获取并输出对象中的属性值。

    示例4-11 调用attributes对象获取全部的属性值

1.功能描述

    在构建并实例化一个模型对象后,首先在浏览器的控制台中输出该对象的整个attributes内容,然后以遍历的方式在浏览器的控制台中分别输出attributes中的每一项值。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
//直接输出attributes对象
console.log(stuE.attributes);
//遍历后输出attributes对象中的每项属性和值
var attrs = stuE.attributes;
for(var i in attrs){
	console.log(i+":"+stuE.attributes[i]);
}

2.源码分析

    从上图中可以看出,直接输出attributes对象时,它是以JSON格式的形式形式显示的,因此下列两端代码是等价的。

console.log(stuE.attributes);

等价于:

console.log(stuE.toJSON());

    以遍历的方式也可以获取attributes对象中的某项属性值,如上图中2、3、4行所示。因此,可以针对某项属性值进行修改。


注意:

    虽然这种方式也可以获取对象的属性值,但这种方法的使用不会触发任何事件,容易产生数据的异常。


4.3.2  previous和previousAttributes方法返回数据

1.功能描述

    在构建并实例化一个模型对象后,第一次使用set方法重置对象的全部属性值,并将重置后对象的previousAttributes输出至浏览器的控制台中。接下来,第二次使用set方法重置对象的全部属性值,同时将重置后对象的previousAttributes输出至浏览器的控制台中,观察两次输出的变化。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
console.log(stuE.toJSON());
console.log(stuE.previousAttributes());
console.log("-----");
stuE.set({
	Code:"10107",
	Name:"杰尼龟",
	Score:720
});
console.log(stuE.toJSON());
console.log(stuE.previousAttributes());

2.源码分析

    在上述代码中,首先第一次使用set方法重置stuE对象属性值,分别调用对象的toJSON和previousAttributes方法输出对象当前数据和上一个状态的数据。然后,第二次使用set方法重置stuE对象属性值,再次调用相关方法输出对象当前数据和上一个状态的数据。

    从上图中可以看出,第2行显示的对象值是第1行重置数据之前的状态数据,即初始化数据。而再次重置数据之后,previousAttributes方法获取的数据值也随之发生了变化。图中第5行显示的对象值是第4行重置数据之前的状态数据,即第一次调用对象set方法重置后的数据。由此可见,previousAttributes方法总是获取对象重置数据之前的上一个状态数据,而非初始化的数据。


4.3.3 set方法的内部顺序(略)


4.4 同步数据到服务器

    在Backbone中,客户端的静态页面与服务器之间的数据,可以通过save、fetch、destory方法分别实现在服务器中保存、获取、删除数据的操作,通过这些方法可以实现客户端与服务器之间的无缝式连接,完成客户端数据与服务器的同步。接下来逐一进行介绍。


4.4.1 save方法

    在Backbone中,对象save方法的功能是在服务器中保存客户端发送的数据,在数据发送过程中,还能通过模型内部的isNew方法检测数据是否是新建还是更新。如果是新创建,通过POST方法发送,否则通过PUT方式发送。服务器根据数据发送的方式进行数据添加或更新操作,并向客户端返回操作结果,客户端根据获取的操作结果,进行下一步的操作。

    示例4-13 使用save方法发送数据

    当一个实例化后的模型对象在模型中设置服务器请求地址url属性后,就可以直接调用对象的save方法,向服务器发送数据。接下来通过简单的示例来演示save方法向服务器发送数据的过程。

1.功能描述

    首先,在构建模型类时添加url属性,指定save方法发送数据时的请求路径。然后实例化一个模型对象,并调用该对象的save方法,此时观察浏览器控制台的数据请求。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	url:"../servlet/StudentServlet",
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
});
stuE.save();

3.页面效果

    在上述代码中,首先在模型中添加一个用于执行服务器请求地址的url属性,并设置该属性的值。然后,调用对象的set方法重置一次模型对象的属性值,并调用save方法进行数据保存。在保存过程中,将向已设置的url属性值发送本次重置的对象数据,保存至服务器中。执行上述代码之后,在Firefox浏览器控制台获取的请求数据效果如上图所示。

4.源码分析

    从上图可以看出,此次调用save方法发送数据的方式因为是新增加数据,所以是POST方式。请求返回200,表示此次数据发送的请求地址是成功的。另外,数据发送的格式是JSON,数据内容为最后一次使用set方法重置的属性值。


    示例4-14 使用save方法接收返回值

    使用对象的save方法发送数据至服务器后,服务器将接收到的数据写入数据库,实现保存或修改的功能。操作完成后,将向客户端返回一个成功或失败的标志,客户端根据这一返回值进行下一步的操作。

1.功能描述

    在示例4-13的基础之上修改代码,调用save方法发送数据时,添加一个success函数,通过该函数的参数可以传回服务器的返回值。获取成功后,将返回值的内容输出至浏览器的控制台中。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	url:"../servlet/StudentServlet",
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
});
stuE.save(null,{
	success:function(model,response){
		console.log(response);	
	}
});
服务器端代码

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

public class StudentServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String code = request.getParameter("Code");
		String name = request.getParameter("Name");
		String score = request.getParameter("Score");
		System.out.println("code---->"+code);
		System.out.println("name---->"+name);
		System.out.println("score---->"+score);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("code", "777");
//		response.getWriter().println("{\"code\":\"888\"}");//注意JSON数据必须键值都带双引号
		response.getWriter().println(jsonObject.toString());
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

2.页面效果

    本次修改的前端页面代码中,在调用对象的save方法时,设置一个success函数,当成功接收服务器返回值时自动执行。在该函数中,通过response参数获取服务器返回的JSON格式数据,并将该值显示在浏览器的控制台中。最终在Firefox浏览器控制台输出效果如上图所示。

3.源码分析

    从上图中可以看出,服务请求是正确的,并有响应,响应为JSON格式的数据,客户端通过在success函数的参数response获取该返回的code值;此外,也可以在save方法中添加一个error函数,当服务器出现返回错误时执行该函数。



    示例4-15 使用save方法时设置wait设置
    在调用save方法向服务器保存数据时,不仅可以在配置对象中添加success或error函数,还可以将wait属性值设置为true。在配置对象中,将wait属性值设置为true时,将会调用validate方法,对发送数据的有效性进行验证。如果没有通过验证,将不会向服务器发送数据,而对象的数据会进行回滚,返回上一状态。此外,当向服务器发送数据时,如果请求失败也将导致数据回滚,返回上一状态。

1.功能描述

    是示例4-14的基础之上修改代码。首先,调用save方法发送数据请求时,将配置对象中的wait属性值设置为true或不设置该属性;然后分别在浏览器的控制台中观察这两种不同设置情况下数据发送的内容。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	url:"haha",//不可访问的url
	defaults:{
		Code:"10001",
		Name:"张三",
		Score:100
	}
});
var stuE = new student();
stuE.save({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
},{
	success:function(model,response){
		console.log(response);
	},
	wait:true
});
console.log(stuE.attributes);

当wait属性为true时



当wait属性为false时


2.源码分析

    在上述代码中,首先将模型中的url属性设置为一个不可访问的服务器地址,造成请求异常。调用save方法向服务器发送数据时,直接通过该方法的第一个参数进行设置并发送,并在save方法的可选参数中添加success函数,将wait属性设置为true,表示需要验证才能更新模型中数据。最后,在浏览器的控制台中,以JSON的格式输出对象stuE的全部数据。

    从上图中可以看出,向服务器发送数据的请求地址异常时,如果在save方法中将wait属性值设置为true时,数据将进行回滚;如果没有设置wait属性,不论服务器是否接收或发送数据是否符合验证规则,都将原有数据进行重置,更新为最新的对象数据。

    通过本示例的演示可以看出,通过调用save方法中的第一个参数,可以实现既向服务器发送数据,又重置本地模型数据的功能。该参数可以通过对象的方式重置多个属性,也可以通过调用两个参数,采用key/value的方式实现某个属性值的发送与重置。


4.4.2 fetah方法

    与save方法不同,fetah方法的功能是从服务器端获取数据,常用于数据模型初始化或数据恢复,它的使用格式与save方法差不多,该方法采用get方式请求服务器中的数据,当请求成功后,将调用set方法重置模型的this.attributes对象。同时,如果重置成功,调用success函数,否则直接返回。下面通过一个简单的示例来演示fetch方法从服务器获取数据的过程。

    示例4-16 使用fetch方法获取服务器数据

1.功能描述

    在构建模型类时,首先设置url属性,用于指定fetch方法获取数据时的请求路径。然后实例化一个模型对象,并调用该对象的fetch方法。在调用过程中,添加该方法的两个回调函数success和error,在第一个函数中,通过浏览器的控制台输出获取的数据内容。

var student = Backbone.Model.extend({
	initialize:function(){
		//构造函数
	},
	url:"../servlet/StudentServlet"
});
var stuE = new student();
stuE.fetch({
	success:function(model,response){
		console.log(stuE.toJSON());
	},
	error:function(err){
		console.log(err);
	}
});

2.源码分析

    在本次示例的前端页面代码中,首先通过在数据模型中添加一个url属性值,来设置fetch方法请求数据的地址。然后,实例化一个模型数据对象,并调用该对象的fetch方法按指定的url路径获取服务器返回的数据。最后,在fetch方法的配置对象中添加一个success函数,数据请求成功后调用该函数,将当前stuE对象的内容以JSON格式输出在浏览器的控制台。

    从上图中可以看出,当对象调用fetch方法请求数据成功时,已将服务器端的JSON格式数据通过调用set方法重置于当前的数据模型中,因此可以调用toJSON方法将对象stuE的数据以JSON格式输出在控制台中。


4.4.3 destory方法

    在Backbone中,当调用对象的destory方法时,将以DELETE请求方式向服务器发送对象的ID数据,服务器接收该数据后删除对应的数据记录,并向客户端发送删除成功的标志。

    由于是删除对象的数据,因此在调用destroy方法时,必须发送ID号属性,如果不存在该属性,可以通过idAttribute属性进行设置,否则不会发送数据请求操作。

    此外,在调用destroy方法的过程中,也可以配置对象中添加success、error函数或将wait属性值设置为true,当请求服务器删除数据成功并接收返回值后,不仅触发绑定的destroy事件,而且还调用success函数;当请求服务器失败时,如果wait属性值为true,则不会触发绑定的destroy事件,反之将会触发绑定的destroy事件并且执行error方法,下面通过一个简单的示例来演示destroy方法从服务器删除数据的过程。


    示例4-17 使用destroy方法从服务器删除数据

1.功能描述

    在构建模型类时,首先通过url属性指定删除数据的请求路径,并添加idAttribute属性指定ID对应的属性名称。然后实例化一个模型对象,并调用该对象的destroy方法。在调用该方法时,通过success回调函数获取请求传回的内容,并将内容输出至于浏览器控制台中。

var student = Backbone.Model.extend({
	//构造函数
	initialize:function(){
		this.on("destroy",function(){
			console.log("正在调用destroy方法");
		});
	},
	url:"../servlet/StudentDeleteServlet",
	idAttribute:"Code"
});
var stuE = new student({
	Code:"10107"
});
stuE.destroy({
	success:function(model,response){
		if(response.code=="0"){
			console.log("Code为"+model.get("Code")+"的数据已删除");
		}
	},
	error:function(err){
		console.log("数据删除异常");
	},
	wait:true
});
服务器端代码
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

public class StudentDeleteServlet extends HttpServlet {

	/**
	 * 注意因为是DELETE请求,所以不是用doGet和doPost来处理这个请求了
	 */
	@Override
	public void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("code", "0");
		response.getWriter().print(jsonObject.toString());
	}

}


当URL正确时


当URL错误时


2.源码分析

    在本示例的前端页面代码中,首先为了向服务端发送删除数据的ID号,通过idAttribute属性将Code名称设置为数据请求时的ID号属性。然后,在构造函数中绑定destroy事件,当删除数据请求成功开始删除本地模型中对应数据时,将会触发该事件。

    最后,实例化一个名称为stuE的对象,并调用该对象的destroy方法。在调用方法的过程中,添加了success和error函数,并将wait属性值设置为true,当服务器成功删除指定ID号的数据时,执行success函数。在该函数中,根据服务器返回的标志值将在浏览器的控制台中输出删除成功的信息。

    当服务器成功删除数据并向客户端返回删除成功标志后,客户端进行本地模型数据的删除,此时会触发已绑定的destroy事件然后执行success函数,根据服务端返回的标志,在浏览器的控制台输出删除成功的信息。

    当请求服务器删除数据出现异常时,由于在destroy方法中配置对象的wait属性设置为true,因此不会触发已绑定的destroy事件,只执行error函数,将错误信息输出至浏览器的控制台中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值