`

Backbone入门指南(四):Model(数据模型)

阅读更多

7. Model (数据模型)

  Model是Backbone中所有数据模型的基类,用于封装原始数据,并提供对数据进行操作的方法,我们一般通过继承的方式来扩展和使用它。

  如果你做过数据库开发,可能对ORM(对象关系映射)不会陌生,而Backbone中的Model就像是映射出来的一个数据对象,它可以对应到数据库中的某一条记录,并通过操作对象,将数据自动同步到服务器数据库。(下一节即将介绍的Collection就像映射出的一个数据集合,它可以对应到数据库中的某一张或多张关联表)。

7.1 创建数据模型

  我们先通过一段代码来看看如何创建数据模型:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    defaults : {
        name : 'unknown',
        author : 'unknown',
        price : 0
    }
});

// 实例化模型对象
var javabook = new Book({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});
 

 

  我们通过Model.extend方法,定义一个自己的模型类Book。

  Backbone模块类(包括子类)都包含一个extend静态方法用于实现继承。给extend方法传递的第一个参数应该是一个对象,对象中的属性和方法将被添加到子类,我们可以通过extend方法扩展子类或重载父类的方法。

  从Backbone模块类继承的子类,都包含一个__super__静态属性,这是一个指向父类原型对象的引用,例如:

 

var Book = Backbone.Model.extend({
    constructor: function() {
        Book.__super__.constructor.call(this)
    }
});
 

 

  在这个例子中,我们重载了Model类的构造函数,但我们希望在子类被实例化时,调用父类的构造函数,因此我们可以通过引用Book.__super__.constructor来调用它。

  实际上我们一般并不会重载模块类的constructor方法,因为在Backbone中所有的模块类都提供了一个initialize方法,用于避免在子类中重载模块类的构造函数,当模块类的构造函数执行完成后会自动调用initialize方法。


  回到本节的第一个例子,我们在定义Book类的时候,传递了一个defaults参数,它用于定义模型数据的默认状态,虽然我们在创建Book实例后再添加它们,但为每个数据模型定义属性列表和默认值,是一个好的编码习惯。

  最后,我们通过new关键字,创建了一个Book的实例,并向它的构造函数中传递了一系列初始化数据,它们将覆盖defaults中定义的默认状态。

7.2 初始化和读取数据

  在我们定义好一个模型类之后,可以通过new关键字实例化该模型的对象。

  如果模型类在定义时设置了defaults默认数据,这些数据将被复制到每一个实例化的对象中,如:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    defaults : {
        name : 'unknown',
        author : 'unknown',
        price : 0
    }
});

// 实例化模型对象
var javabook = new Book();
 

 

  上面的代码创建了一个Book实例javabook,它包含了模型类在定义时的默认数据。

  我们将实例化的代码稍作修改:

 

// 实例化模型对象
var javabook = new Book({
    name : 'Thinking in Java'
});

// 通过get和escape()方法获取模型中的数据
var name = javabook.get('name');
var author = javabook.escape('author');
var price = javabook.get('price');

// 在控制台输出模型中的数据name
console.log(name); // 输出Thinking in Java
console.log(author); // 输出unknown
console.log(price); // 输出0
 

 

  我们在实例化对象时传递了初始数据,它将覆盖Book类定义时defaults中的默认数据,这一点很容易理解。


  上面的例子中我们通过get()和escape()方法获取模型中的数据,它们的区别在于:

 

  • get()方法用于直接返回数据
  • escape()方法先将数据中包含的HTML字符转换为实体形式(例如它会将双引号转换为"形式)再返回,用于避免XSS攻击。

 


  模型将原始数据存放在对象的attributes属性中,因此我们也可以通过javabook.attributes属性直接读取和操作这些数据,例如:

 

// 在控制台直接输出对象的attributes属性
console.dir(javabook.attributes);

// 控制台输出结果
// {
//     author: 'unknown',
//     name: 'Thinking in Java',
//     price: 0
// }
 

 

  但通常并不会这样做,因为模型中数据状态的变化会触发一系列事件、同步等动作,直接操作attributes中的数据可能导致对象状态异常。更安全的做法是:通过get()或escape()方法读取数据,通过set()等方法操作数据。

7.3 修改数据

  我们通常可以调用模型对象的set()方法,来修改模型中的数据,例如:

 

// 实例化模型对象
var javabook = new Book();

// 通过set方法设置模型数据
javabook.set('name', 'Java7入门经典');
javabook.set('author', 'Ivor Horton');
javabook.set('price', 88.50);

// 获取数据并将数据输出到控制台
var name = javabook.get('name');
var author = javabook.get('author');
var price = javabook.get('price');

console.log(name); // 输出Java7入门经典
console.log(author); // 输出Ivor Horton
console.log(price); // 输出88.50
set()方法也允许同时设置多个属性,例如:
javabook.set({
    name : 'Java7入门经典',
    author : 'Ivor Horton',
    price : 88.50
});
 

 

  当调用set()方法修改模型中的数据时,会触发一系列事件,我们常常通过监听这些事件,来动态调整界面中数据的显示,我们先来看一个例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    defaults : {
        name : 'unknown',
        author : 'unknown',
        price : 0
    }
});

// 实例化模型对象
var javabook = new Book();

// 监听模型"change"事件
javabook.on('change', function(model) {
    console.log('change事件被触发');
});
// 监听模型"change:name"事件
javabook.on('change:name', function(model, value) {
    console.log('change:name事件被触发');
});
// 监听模型"change:author"事件
javabook.on('change:author', function(model, value) {
    console.log('change:author事件被触发');
});
// 通过set()方法设置数据
javabook.set({
    name : 'Thinking in Java',
    author : 'unknown',
    price : 395.70
});

// 控制台输出结果:
// change:name事件被触发
// change事件被触发
 

 

  在本例中,我们监听了模型对象的change事件,该事件在模型对象的任何数据发生改变时被触发,change事件触发时,会将当前模型作为参数传递给监听函数。

  我们还监听了change:name和change:author两个属性事件,属性事件是当模型中对应属性的数据发生改变时被触发,属性事件按照“change:属性名”来命名,因此它并不固定。属性事件触发时,会将当前模型和最新的数据作为参数传递给监听函数。

  本例执行后在控制台的输出结果为:

  “change:name事件被触发

  change事件被触发”

  从结果中看,并没有触发我们监听的change:author事件,因为在调用set()方法时,它会在内部检查新的数据较上一次是否发生变化,只有发生变化的数据才会被设置和触发监听事件。

  另一个细节是,我们先监听了change事件,然后监听了属性事件,但事件在触发时,总是会先触发属性事件,然后再触发change事件。


  Backbone允许我们在修改模型数据时获取上一个状态的数据,这常常用于数据比较和数据回滚。

  例如在下面的例子中,我们希望当price价格被改变时,提示用户价格的变化情况:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    defaults : {
        name : 'unknown',
        author : 'unknown',
        price : 0
    }
});

// 实例化模型对象
var javabook = new Book();

// 监听"change:price"事件
javabook.on('change:price', function(model, value) {
    var price = model.get('price');

    if(price < value) {
        console.log('价格上涨了' + (value - price) + '元.');
    } else if(price > value) {
        console.log('价格下降了' + (value - price) + '元.');
    } else {
        console.log('价格没有发生变化.');
    }
});
// 设置新的价格
javabook.set('price', 50);

// 控制台输出结果:
// 价格没有发生变化.
 

 

  我们通过监听change:price事件来监听价格的变化,并希望将最新的价格和当前(上一次)的价格作比较,但控制台的输出结果却是“价格没有发生变化.”。这是因为当change事件或属性事件被触发时,模型中的数据已经被修改,因此通过get()方法获取到的是模型中最新的数据。

  这时,我们可以通过previous()和previousAttributes()方法来获取数据被修改之前的状态。

  我们将代码稍作修改,只需要修改监听事件的函数即可:

 

// 监听"change:price"事件
javabook.on('change:price', function(model, value) {
    var price = model.previous('price');

    if(price < value) {
        console.log('价格上涨了' + (value - price) + '元.');
    } else if(price > value) {
        console.log('价格下降了' + (value - price) + '元.');
    } else {
        console.log('价格没有发生变化.');
    }
});
 

 

  我们将get()方法修改为previous()方法,用来获取价格在修改之前的状态,此时控制台输出的结果为:“价格上涨了50元.”

 

  • previous()方法接收一个属性名,并返回该属性在修改之前的状态;
  • previousAttributes()方法返回一个对象,该对象包含上一个状态的所有数据。

 

  需要注意的是,previous()和previousAttributes()方法只能在数据修改过程中调用(即在模型的change事件和属性事件中调用),比如下面的例子就是错误的调用方法:

 

// 设置新的价格
javabook.set('price', 50);

var prevPrice = javabook.previous('price');
var newPrice = javabook.get('price');

if(prevPrice < newPrice) {
    console.log('价格上涨了' + (newPrice - prevPrice) + '元.');
} else if(prevPrice > newPrice) {
    console.log('价格下降了' + (newPrice - prevPrice) + '元.');
} else {
    console.log('价格没有发生变化.');
}

// 控制台输出结果:
// 价格没有发生变化.
 

 

  控制台输出的结果是“价格没有发生变化.”,因为在set()方法被调用完毕后,模型的上一个状态也会被新数据替换。

  (有一种特殊情况是当我们使用了silent配置时,上面的代码可以得到我们想要的结果,关于silent配置将在后面“数据验证”章节中介绍)

7.4 数据验证

  Backbone模型提供了一套数据验证机制,确保我们在模型中存储的数据都是通过验证的,我们通过下面的例子来说明这套验证机制:

 

  执行这段代码,你会在控制台看到这段信息:“书籍价格不应低于1元.”

  在定义模型类时,我们可以添加一个validate方法,该方法会在模型中的数据发生改变之前被自动调用(就像我们通过set()方法修改数据时一样)。

  validate方法接收一个参数,表示需要进行验证的数据集合,如果validate方法没有任何返回值(即undefined),则表示验证通过;如果验证不通过,我们常常会返回一个错误字符串或自定义对象。但实际上,当你返回一个false也会被认为验证通过,因为Backbone内部会将validate的返回值转换为布尔类型,如果为false则认为验证通过,反之则认为不通过(虽然这听起来有些别扭)。

  当validate验证不通过时,会触发error事件,并将模型对象和validate方法的返回值传递给error事件的监听函数(就像例子中的那样)。

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    validate : function(data) {
        if(data.price < 1) {
            return '书籍价格不应低于1元.';
        }
    }
});

var javabook = new Book();

// 监听error事件,当验证失败时触发
javabook.on('error', function(model, error) {
    console.log(error);
});

javabook.set('price', 0);
 

 

  上面的例子中,我们监听了javabook对象的error事件,用于在验证不通过时提示用户。但在某个场景下,我希望以另一种方式提示用户,我可以在error监听函数中判断是否处于这种场景下,然后作出不同的提示,但这显然不是最好的办法。

  因此,Backbone提供了另一种方式对error事件进行覆盖,来看看这个例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    validate : function(data) {
        if(data.price < 1) {
            return '书籍价格不应低于1元.';
        }
        return false;
    }
});

var javabook = new Book({
    price : 50
});

// 监听error事件,当验证失败时触发
javabook.on('error', function(model, error) {
    console.log(error);
});

// 在调用set()方法时,传递了一个配置对象,包含自定义的error处理方法
javabook.set('price', 0, {
    error : function(model, error) {
        console.log('自定义错误:' + error);
    }
});
 

 

  在这段代码中,我们在调用set()方法时,传递了第三个参数,它是一个用于描述配置信息的对象,我们设定了一个error函数。当validate方法验证失败时,会优先调用配置中传递的error函数,如果没有传递error函数,则会触发error事件。


  如果我们不希望对数据进行验证,可以在调用set()方法时传递一个silent配置,silent配置用于忽略验证规则,并且它不会触发change和error等事件。

  在上面例子的基础上,我们修改一下set()方法的调用方式:

 

javabook.set('price', 0, {
    silent : true
});
 

 

  我们设置了一个非法的数据,同时指定了silent配置,结果并没有触发error事件,因为它并没有调用validate方法对数据进行验证。

  我们再将set()方法的调用代码修改一下:

 

javabook.set('price', 0, {
    silent : true
});

javabook.set('name', 'Thinking in Java');
 

 

  执行这段代码,控制会再次输出“书籍价格不应低于1元.”。

  从结果中可以看出,silent配置仅仅是忽略对本次数据的验证,而在下一次数据发生变化时,会重新执行validate方法进行验证。


  使用silent配置设置数据时,模型也不会触发change事件,这这意味着数据在业务层面并没有真正被设置到模型中,这有利于我们及时对错误的数据进行恢复和回滚。

  我们来看一个数据回滚的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend();

// price的初始值为50
javabook = new Book({
	price : 50
});

// 我们设置一个非法数据并绕过验证
javabook.set('price', 0.2, {
	silent : true
});

// 检查数据非法,回滚数据
if(javabook.get('price') < 1) {
	var value = javabook.previous('price');
	javabook.set('price', value);
}
 

 

  在本例中,我们在实例化Book模型时设置price的初始化数据为50,然后将price设置为一个非法数据并绕过验证,最后调用previous()方法获取数据的上一个状态,并重新设置。

  值得注意的是,在上一节中我们提到,previous()方法只有在change事件的监听函数中才能获取数据的上一个状态。而这里我并没有这样做,因为当我们使用silent配置时,设置的数据仅仅是被临时存放在模型,这种情况下Backbone允许我们随时调用previous()和previousAttributes()方法获取数据的上一个状态。

  (数据的上一个状态会在下一次调用set()方法将数据设置到模型中后自动清除)

7.5 删除数据

  Backbone中删除模型数据的操作相对简单,我们常常用unset()和clear()方法来删除模型中的数据:

 

  • unset()方法用于删除对象中指定的属性和数据
  • clear()方法用于删除模型中所有的属性和数据

 


  我们来看一个unset()方法的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend();

// 实例化模型对象
var javabook = new Book({
    name : 'Java7入门经典',
    author : 'Ivor Horton',
    price : 88.50
});

// 输出: Java7入门经典
console.log(javabook.get('name'));

// 删除对象name属性
javabook.unset('name');

// 输出: undefined
console.log(javabook.get('name'));
当我们对模型的name属性执行unset()方法后,模型内部会使用delete关键字将name属性从对象中删除。

clear()方法与unset()方法执行过程类似,但clear()方法会删除模型中的所有数据,例如:
// 定义Book模型类
var Book = Backbone.Model.extend();

// 实例化模型对象
var javabook = new Book({
    name : 'Java7入门经典',
    author : 'Ivor Horton',
    price : 88.50
});

// 删除对象name属性
javabook.clear();

// 以下均输出: undefined
console.log(javabook.get('name'));
console.log(javabook.get('author'));
console.log(javabook.get('price'));
 

 

  在调用unset()和clear()方法清除模型数据时,会触发change事件,我们也同样可以在change事件的监听函数中通过previous()和previousAttributes()方法获取数据的上一个状态。

7.6 将模型数据同步到服务器

  Backbone提供了与服务器数据的无缝连接,我们只需要操作本地Model对象,Backbone就会按照规则自动将数据同步到服务器。

  如果需要使用Backbone默认的数据同步特性,请确定你的服务器数据接口已经支持了REST架构。在REST架构中,客户端会通过请求头中的Request Method告诉服务器我们将要进行的操作(包括create、read、update和delete,它们对应的Request Method分别为POST、GET、PUT和DELETE),而对于没有良好支持REST发送方式的浏览器,Backbone会使用另外一些方法来实现,这在本节中会详细讨论。


  在讨论数据同步相关方法之前,你需要先了解一些Backbone中与数据同步息息相关的内容:

  数据标识:

  设想一下,如果我们需要通过服务器接口删除一条数据,仅仅在报文头中通过Request Method标识告诉服务器进行delete操作是不够的,更重要的是还需要告诉服务器删除哪一条数据,这需要我们传递给服务器一个数据的唯一标识(例如记录id)。

  Backbone中每一个模型对象都有一个唯一标识,默认名称为id,你可以通过idAttribute属性来修改它的名称。

  id应该由服务器端创建并保存在数据库中,在与服务器的每一次交互中,模型会自动在URL后面加上id,而对于客户端新建的模型,在保存时不会在URL后加上id标识(我们可以通过模型的isNew()方法来检查,该模型对象是否是由客户端新建的)。

  URL规则:

  Backbone默认使用PATHINFO的方式来访问服务器接口。

  例如:我们在删除一个模型数据时,模型会在报文头的Request Method中声明delete操作,并在服务器接口后自动加上模型id,格式类似于http://urlRoot/10001,其中urlRoot是我们设置的服务器接口地址,而10001是模型id。请注意它是通过URL路径的方式自动追加到接口地址后的,因此服务器也必须要支持PATHINFO的解析方式。

  使用PATHINFO方式,因为它更直观,更利于SEO,还可以避免与Backbone中的路由器发生混淆(关于路由器将在后面的章节中介绍)。


  如果我们希望让Backbone自动与服务器接口进行交互,首先应该配置模型的URL,Backbone支持3种方式的URL配置:

  第一种是urlRoot方式:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book({
    id : 1001,
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});

// 保存数据
javabook.save();
 

 

  在这个例子中,我们创建了一个Book模型的实例,并调用save()方法将数据保存到服务器。(可能你对save()方法还不太了解,但这并不重要,因为我们马上就会讲到它,现在你只需知道我们用它将模型中的数据保存到服务器)

  你可以抓包查看请求记录,你能看到请求的接口地址为:http://localhost/service/1001

  其中localhost是我的主机名,因为我在本地搭建了一个Web服务器环境。

  service是该模型的接口地址,是我们在定义Book类时设置的urlRoot。

  1001是模型的唯一标识(id),我们之前说过,模型的id应该是由服务器返回的,对应到数据库中的某一条记录,但这里为了能直观的测试,我们假设已经从服务器端拿到了数据,且它的id为1001。

  这段内容很容易理解,接下来,我们将save()方法换成destroy()方法(该方法用于将模型中的数据从服务器删除):

 

// 删除数据
javabook.destroy();
 

 

  你能看到请求的接口地址仍然为:http://localhost/service/1001。这并不奇怪,如果你细心观察,会发现两次请求头中的Request Method参数分别为PUT和DELETE,服务器接口会根据它来判断你所做的操作。

  如果你的浏览器不支持REST发送方式,你可能会看到Request Method始终是POST类型,且在Form Data中会多出一个_method参数,PUT和DELETE操作名被放在了这个_method参数中。这是Backbone为了适配低版本浏览器而设计的另一种方法,你的服务器接口也必须同时支持这种方式。


  我们再来看第二种URL方式的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
urlRoot : '/service',
url : '/javaservice'
});

// 创建实例
var javabook = new Book({
    id : 1001,
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});

// 保存数据
javabook.save();
 

 

  在这个例子中,我们在定义Book类时,新增了参数url,执行这段代码,你会发现请求的接口地址为http://localhost/javaservice。它没有再使用urlRoot定义的参数,也没有将模型的id追加到接口地址中,urlRoot和url参数我们一般只会同时定义一个,它们的区别在于:

  urlRoot参数表示服务器接口地址的根目录,我们无法直接访问它,只能通过连接模型id来组成一个最终的接口地址

  url参数表示服务器的接口地址是已知的,我们无需让Backbone自动连接模型id(这可能是在url本身已经设置了模型id,或者不需要传递模型id)

  如果同时设置了urlRoot和url参数,url参数的优先级会高于urlRoot。

  (另一个细节是,url参数不一定是固定的字符串,也可以是一个函数,最终使用的接口地址是这个函数的返回值。)


  最后一种URL方式的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service',
    url : '/javaservice'
});

// 创建实例
var javabook = new Book({
    id : 1001,
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});

// 保存数据
javabook.save(null, {
    url: '/myservice'
});
 

 

  在这个例子中,我们在调用save()方法的时候传递了一个配置对象,它包含一个url配置项,最终抓包看到的请求地址是http://localhost/myservice。因此你可以得知,通过调用方法时传递的url参数优先级会高于模型定义时配置的url和urlRoot参数。


  在Backbone中,模型对象提供了3个方法用于和服务器保持数据同步:

 

  • save()方法:在服务器创建或修改数据
  • fetch()方法:从服务器获取数据
  • destroy()方法:从服务器移除数据

 

  下面我们将依次介绍这些方法的使用:


  save()方法:

  save()方法用于将模型的数据保存到服务器,它可能是一条新的数据,也可能是修改服务器现有的某一条数据,这取决于模型中是否存在id(唯一标识)。

  首先我们来看一个创建数据的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book();

// 设置初始化数据
javabook.set({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});

// 从将数据保存到服务器
javabook.save();
 

 

  在这个例子中,我们创建了一个新的Book实例,并设置了一些数据(实际上它们可能是由用户输入的),我们通过save()方法将这些数据提交到服务器。

  如果你抓包看一下报文头信息,能看到Request Method参数为POST,这是因为模型内部会通过isNew()方法检查是否为客户端新建,如果是客户端新建的数据,会通过POST方式发送。如果是修改服务器现有的数据,则通过PUT方式发送。

  如果服务器接口的报文体中没有返回任何数据,你会发现保存之后的模型较之前没有发生任何变化,在你下一次调用save()方法的时候,它仍然会以POST方式通知服务器创建一条新的数据。

  这是因为模型对象并没有获取到刚刚服务器创建成功的记录id,因此我们希望服务器接口在将数据保存成功之后,同时将新的id返回给我们,就像这样:

 

{
    "id" : "1001",
    "name" : "Thinking in Java(修订版)",
    "author" : "Bruce Eckel",
    "price" : "395.70"
}
 

 

  这一段是服务器接口返回的数据,它除了返回新记录的id,还返回了修改后的name数据(当然,你也可以只返回新记录的id,我们常常都是这样做的)。这时我们再来看现在模型中的数据,它多了一个id属性,并且name属性的值也发生了变化,也就是说模型使用服务器返回的最新数据替换了之前的数据。

  我们将代码稍作修改:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book();

// 设置初始化数据
javabook.set({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});

// 将数据保存到服务器
javabook.save(null, {
    success : function(model) {
        // 数据保存成功之后, 修改price属性并重新保存
        javabook.set({
            price : 388.00
        });
        javabook.save();
    }
});
 

 

  我们修改了save()方法的调用参数,像例子中那样,你可以设置一个success回调函数用来表示保存成功之后将要进行操作(你也可以设置一个error回调函数用来表示保存失败时将要进行的操作)。

  在数据保存成功之后,我们将修改模型的price值,并从新调用save()方法保存数据。

  我们抓包看一下请求头,发生了一些什么变化:

  Request Method变成了PUT。

  请求的接口地址变成了http://localhost/service/1001(这与我们刚刚讨论的URL配置有关,如果不明白可以重新阅读本节)。

  当然,还有提交的数据也变成了我们修改后的。


  在调用save()方法时,我们可以传递一个配置项对象,上面我们已经使用它传递了一个success回调函数。

  在配置项中,还可以包含一个wait配置,如果我们传递了wait配置为true,那么数据会在被提交到服务器之前进行验证,当服务器没有响应新数据(或响应失败)时,模型中的数据会被还原为修改前的状态。如果没有传递wait配置,那么无论服务器是否保存成功,模型数据均会被修改为最新的状态、或服务器返回的数据。

  我们还是用一个例子来说明:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    defaults : {
        name : 'unknown',
        author : 'unknown',
        price : 0
    },
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book();

// 从将数据保存到服务器
javabook.save({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
}, {
    wait : true
});
 

 

  请运行这个例子中的代码,并且将服务器接口返回的数据设置为空(或404状态),你能看到在save()方法调用完成之后,模型中的数据被恢复成最初defaults中定义的数据,因为我们在调用save()方法时传递了wait配置。(你也可以试着将wait配置去掉,然后再运行它,你会发现虽然服务器接口并没有返回数据或保存成功,但模型对象中仍然保持着最新的数据)


  正如我们最开始所讲得那样,save()方法用于添加一条新的数据到服务器,或修改现有的一条数据。

  其实save()方法也可以同时实现数据修改和保存,例如:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book();

// 从将数据保存到服务器
javabook.save({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});
 

 

  在本例中,我们在调用时将数据传递给save()方法,而不是先通过set()方法设置数据。当然,你也可以像set()方法一样,只设置某一个值:

 

javabook.save('name', 'Thinking in Java');
 

 

  无论你通过什么方式来保存数据,它都会自动将数据同步到服务器接口(如果你没有设置url或urlRoot参数,那么所有的操作只会在本地进行)。


  我们来讨论另一个问题:上面提到服务器接口返回的数据会被覆盖到当前模型中,在刚刚的例子里,接口返回的数据就是模型需要的数据。而实际开发中往往并没有这么顺利,我们接口返回的数据可能是这样:

 

{
    "resultCode" : "0",
    "error" : "null",
    "data" : [{
        "isNew" : "true",
        "bookId" : "1001",
        "bookName" : "Thinking in Java(修订版)",
        "bookAuthor" : "Bruce Eckel",
        "bookPrice" : "395.70"
    }]
}
 

 

  你能看到,接口返回的数据无论从结构、还是属性名,都与模型中定义的不一样(有时甚至会返回XML或其它格式)。还好Backbone提供了一个parse()方法,用于在将服务器返回的数据覆盖到模型前,对数据进行解析。

  parse()方法默认不会对数据进行解析,因此我们只需要重载该方法,就可以适配上面的数据格式,例如:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service',
    // 重载parse方法解析服务器返回的数据
    parse : function(resp, xhr) {
        var data = resp.data[0];
        return {
            id : data.bookId,
            name : data.bookName,
            author : data.bookAuthor,
            price : data.bookPrice
        }
    }
});

// 创建实例
var javabook = new Book();

// 从将数据保存到服务器
javabook.save({
    name : 'Thinking in Java',
    author : 'Bruce Eckel',
    price : 395.70
});
 

 

  我们重载了parse()方法,并返回了模型中能够使用的格式,这样就可以将服务器接口返回的数据与模型中的数据连接起来。虽然本例中使用了最简单的方式解析,但实际上你可能还会做一些格式化、转换和逻辑工作。


  另外值得注意的一点是:我们常常会在数据保存成功后,对界面做一些改变。此时你可以通过许多种方式实现,例如通过save()方法中的success回调函数。

  但我建议success回调函数中只要做一些与业务逻辑和数据无关的、单纯的界面展现即可(就像控制加载动画的显示隐藏),如果数据保存成功之后涉及到业务逻辑或数据显示,你应该通过监听模型的change事件,并在监听函数中实现它们。虽然Backbone并没有这样的要求和约束,但这样更有利于组织你的代码。


  fetch()方法:

  fetch()方法用于从服务器接口获取模型的默认数据,常常用于模型的数据恢复,它的参数和原理与save()方法类似,因此你可以很容易理解它。

  先让我们看一个例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book();

// 从服务器获取默认数据
javabook.fetch({
    success : function() {
        // 获取数据成功后, 重新读取一次
        javabook.fetch();
    }
});
 

 

  在这个例子中,我们创建了一个空的(没有初始化数据的)Book模型实例,然后通过fetch()方法从服务器接口获取初始化数据,获取数据成功后再次调用fetch()方法重新获取一次。

  我们将服务器接口返回的数据设置为:

 

{
    "id" : "1001",
    "name" : "Thinking in Java",
    "author" : "Bruce Eckel",
    "price" : "395.70"
}
 

 

  你需要注意观察两次请求的URL和参数:

  第一次请求地址为http://localhost/service,Request Method参数为GET

  第二次请求地址为http://localhost/service/1001,Request Method参数为GET

  你会发现第二次在请求地址后加上了1001(模型id),这是因为在第一次获取数据成功后,服务器接口返回的数据会覆盖到模型中,因此模型对象具备了唯一标识(id),因此在此后的每次请求中,模型都会将id加载请求地址后面。


  destroy()方法:

  destroy()方法用于将数据从集合(关于集合我们将在下一章中讨论)和服务器中删除,需要注意的是,该方法并不会清除模型本身的数据。(如果需要删除模型中的数据,请手动调用unset()或clear()方法)

  当你的模型对象从集合和服务器端删除时,只要你不再保持任何对模型对象的引用,那么它会自动从内存中移除。(通常的做法是将引用模型对象的变量或属性设置为null值)

  当调用destroy()方法时,模型会触发destroy事件,所有监听该事件的函数将被调用。

  我们还是通过一个例子来详细了解它:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book({
    id: '1001'
});

// 从服务器删除数据
javabook.destroy();
 

 

  这个例子非常简单,我们创建一个模型后再调用destroy()方法将它销毁。

  请抓包观察请求地址和Request Method:

  我们看到请求地址为:http://localhost/service/1001,Request Method参数为DELETE。它通过Reuqest Method请求参数通知服务器接口将要进行的操作,而请求地址和save()方法及fetch()方法产生的请求地址是相同的,这正体现了我们最开始所说的REST架构。

  在调用destroy()方法时我们同样可以传递一个配置对象,它除了success和error回调函数外,也能像save()方法一样包含一个wait配置,来看下面的例子:

 

// 定义Book模型类
var Book = Backbone.Model.extend({
    urlRoot : '/service'
});

// 创建实例
var javabook = new Book({
    id : '1001'
});

// 监听模型的destroy事件, 在控制台输出字符串
javabook.on('destroy', function() {
    console.log('destroy');
});

// 从服务器删除数据
javabook.destroy({
    wait : true
});
 

 

  如果你的service服务器接口能正常访问,那么你能看到在控制台输出了“destroy”字符串;如果将你的接口设置为响应失败(例如404),那么控制台就不会有输出。

  当我们传递了wait配置后,模型会先请求服务器接口对数据进行删除,当服务器返回状态成功(状态码200)之后,本地才会进行模型的删除操作,最终触发destroy事件。


  如果你想通过Backbone实现数据同步,而不使用RET架构,那么你可以通过重新定义Backbone.sync方法来适配现有的服务器接口。

  在Backbone中,所有与服务器交互的逻辑都定义在Backbone.sync方法中,该方法接收method、model和options三个参数。如果你想重新定义它,可以通过method参数得到需要进行的操作(枚举值为create、read、update和delete),通过model参数得到需要同步的数据,最后根据它们来适配你自己定义的规则即可。

  当然,你也可以将数据同步到本地数据库中,而不是服务器接口,这在开发终端应用时会非常适用。

7.7 小结

  至此,Backbone模型中的核心方法和特性我们都已经讨论完了,我们总结一下本节讨论的主要内容:

  • 模型封装了对象数据,并提供了一系列对数据进行操作的方法
  • 我们可以在定义模型类、实例化模型对象、和调用set()方法来设置模型中的数据
  • 当模型中数据发生改变时,会触发change事件和属性事件
  • 我们可以定义validate方法对模型中的数据进行验证
  • 通过调用save()、fetch()和destroy()方法可以让模型中的数据与服务器保持同步,但在此之前必须设置url或urlRoot属性

  当然,模型类还包含一些实用的方法帮助我们开发,这里就不一一介绍,通过API文档你能轻易地理解它们。

 

8
2
分享到:
评论
11 楼 13770586272 2015-11-25  
10 楼 jia58960 2014-10-27  
klamtine 写道
文章的节奏进度同同类Backbone教程相比拿捏的要好很多,可能是由于版本问题,7.4数据验证部分,Backbone1.1.2下 set 默认不触发 validate事件,需要传额外的参数:

javabook.set('price', 0, [color=darkred]{validate: true}[/color]);


另外,validate未通过默认触发的事件是 invalid,而非 error。所以回调事件代码如下:

javabook.on('invalid', function () { //do something here })


以上。

一开始没看评论,调试了老半天。楼上正解!
9 楼 klamtine 2014-05-31  
文章的节奏进度同同类Backbone教程相比拿捏的要好很多,可能是由于版本问题,7.4数据验证部分,Backbone1.1.2下 set 默认不触发 validate事件,需要传额外的参数:

javabook.set('price', 0, [color=darkred]{validate: true}[/color]);


另外,validate未通过默认触发的事件是 invalid,而非 error。所以回调事件代码如下:

javabook.on('invalid', function () { //do something here })


以上。
8 楼 wdydxf 2014-01-02  
       
7 楼 fansfirst2008 2013-10-27  
刚看了下官方文档:
  "error" (model, xhr, options) — when a model's save call fails on the server.
"invalid" (model, error, options) — when a model's validation fails on the client.

但是那个自定义的错误响应,还真不晓得怎么实现?
6 楼 fansfirst2008 2013-10-27  
感谢楼主的贡献,支持

接2楼, 好像监听不到error事件吧? 我在chrome里面测试,需要改成invalid.
楼主是哪个版本测试的?
5 楼 duni_读你 2013-09-03  
楼主辛苦了,看了你的文章,真是受益匪浅啊。 支持一下
4 楼 nowboy11427 2013-08-29  
感谢楼主的贡献,我感觉非常适合作为 backbone 的入门教材
3 楼 rn131456789 2013-04-18  
Upgrading to 1.0 

Model validation is now only enforced by default in save — not in set unless the {validate:true} option is passed. Model validation now fires an "invalid" event instead of "error".
2 楼 asdf6339 2013-03-21  
var Book = Backbone.Model.extend({ 
    validate : function(data) { 
        if(data.price < 1) { 
            return '书籍价格不应低于1元.'; 
        } 
    } 
}); 
 
var javabook = new Book(); 
 
// 监听error事件,当验证失败时触发 
javabook.on('error', function(model, error) { 
    console.log(error); 
}); 
 
javabook.set('price', 0);  //javabook.set({'price': 0}, { validate : true});


//上面的代码是不会进行数据验证的,set方法默认是不去执行validate方法的,必需加入validate这个属性,本人测试的Backbone v1.0
1 楼 bluedest 2012-12-16  
赞,希望楼主有空研究下emberjs,也写点指南出来。

相关推荐

    backbone 入门指南

    ### Backbone.js入门指南知识点概述 #### 一、为什么需要Backbone.js? Backbone.js是一个轻量级的JavaScript库,它提供了MVC(Model-View-Controller)架构模式的基础实现,帮助开发者更好地组织复杂的Web应用...

    backbone-gulp-starter:使用gulp和骨干网的最小入门项目

    `Backbone.js`的核心概念包括模型(Model)、视图(View)、集合(Collection)和路由器(Router)。它允许开发者用JavaScript对象来组织数据和业务逻辑,同时提供了一种方式将这些数据绑定到DOM元素,实现视图的...

    backbone_quickstart

    **Backbone.js 快速入门指南** Backbone.js 是一个轻量级的JavaScript库,它为构建复杂的Web应用提供了一套结构和模式。这个“backbone_quickstart”项目旨在帮助开发者快速掌握Backbone的核心概念,结合了其他流行...

    marionette_book:木偶+骨干入门

    1. **模型(Model)**: 是应用程序数据的容器,负责处理数据的业务逻辑。 2. **视图(View)**: 负责展示模型的数据,通常与DOM元素关联,并响应用户交互。 3. **集合(Collection)**: 是模型的集合,提供了操作和...

    NX二次开发-属性操作(创建与编辑)

    目前关于属性操作的创建于编辑主要有新旧两个版本,旧版本主要使用UF_ATTR_assign()函数,新版本主要使用UF_ATTR_set_user_attribute()函数。注意在使用新版本是需要初始化。

    编书 机械制图习题集(属性块图框)出版社.dwg

    编书 机械制图习题集(属性块图框)出版社.dwg

    毕业设计物联网实战项目基于 ESP8266 及 1.3 寸 TFT 实现的华为太空人时钟.zip

    【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    【机器人控制】基于MATLAB的不同神经网络控制器性能对比:机器人手臂模型的NNPC、MRC和NARMA-L2控制策略分析(复现论文或解答问题,含详细可运行代码及解释)

    内容概要:本文档提供了三种神经网络控制器(NNPC、MRC和NARMA-L2)在机器人手臂模型上性能比较的MATLAB实现代码及详细解释。首先初始化工作空间并设定仿真参数,包括仿真时间和采样时间等。接着定义了机器人手臂的二阶动力学模型参数,并将其转换为离散时间系统。对于参考信号,可以选择方波或正弦波形式。然后分别实现了三种控制器的具体算法:MRC通过定义参考模型参数并训练神经网络来实现控制;NNPC利用预测模型神经网络并结合优化算法求解控制序列;NARMA-L2则通过两个神经网络分别建模f和g函数,进而实现控制律。最后,对三种控制器进行了性能比较,包括计算均方根误差、最大误差、调节时间等指标,并绘制了响应曲线和跟踪误差曲线。此外,还强调了机器人手臂模型参数的一致性和参考信号设置的规范性,提出了常见问题的解决方案以及性能比较的标准化方法。 适合人群:具备一定编程基础,特别是熟悉MATLAB编程语言的研究人员或工程师,以及对神经网络控制理论有一定了解的技术人员。 使用场景及目标:①理解不同类型的神经网络控制器的工作原理;②掌握在MATLAB中实现这些控制器的方法;③学会如何设置合理的参考信号并保证模型参数的一致性;④能够根据具体的性能指标对比不同控制器的效果,从而选择最适合应用场景的控制器。 其他说明:本文档不仅提供了完整的实验代码,还对每个步骤进行了详细的注释,有助于读者更好地理解每段代码的功能。同时,针对可能出现的问题给出了相应的解决办法,确保实验结果的有效性和可靠性。为了使性能比较更加公平合理,文档还介绍了标准化的测试流程和评估标准,这对于进一步研究和应用具有重要的指导意义。

    《基于YOLOv8的雪场设备识别系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    (源码)基于Python的微信智能聊天机器人.zip

    # 基于Python的微信智能聊天机器人 ## 项目简介 本项目是一个基于Python的微信智能聊天机器人框架,旨在通过ChatGPT的强大对话能力,将微信打造成一个智能助手。该机器人支持私聊和群聊的智能回复、语音识别、图片生成、插件扩展等功能,能够与好友进行多轮对话,并提供丰富的交互体验。项目支持多端部署,包括个人微信、微信公众号和企业微信应用。 ## 项目的主要特性和功能 多端部署支持个人微信、微信公众号和企业微信应用等多种部署方式。 智能对话支持私聊和群聊的智能回复,具备多轮会话上下文记忆功能,支持GPT3、GPT3.5、GPT4等模型。 语音识别可识别语音消息并通过文字或语音回复,支持Azure、Baidu、Google、OpenAI等多种语音模型。 图片生成支持图片生成和图生图功能(如照片修复),可选择DALLE、Stable Diffusion、Replicate等模型。

    Android毕设实战项目基于Android的健身信息管理系统.zip

    【项目资源】: 适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    《基于YOLOv8的医疗废物分类系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    毕业设计物联网实战项目基于腾讯云物联网开发平台的智能台灯,全套腾讯解决方案,可使用微信小程序远程控制.zip

    【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    scipy-0.11.0.tar.gz

    该资源为scipy-0.11.0.tar.gz,欢迎下载使用哦!

    【机械故障仿真】PT500PLUS平行轴齿轮箱故障测试台Machine Vibration & Gearbox Simulator(机械振动-齿轮箱模拟器):转子及齿轮传动故障模拟与数据采集系统设计

    内容概要:PT500PLUS平行轴齿轮箱故障测试台是由瓦伦尼安(VALENIAN)Machine Vibration & Gearbox Simulator(机械振动-齿轮箱模拟器)开发的专业机械故障仿真测试设备。该测试台旨在模拟和研究转子、齿轮传动、轴承及电机系统中的多种常见故障,包括但不限于轴不对中、转子不平衡、机械松动、轴承故障、齿轮故障(如点蚀、磨损、断齿等)以及电机故障(如转子不平衡、轴承故障、匝间短路等)。测试台配备有先进的传感器和数据采集系统,能够实时采集并分析振动、噪声、转速、扭矩等参数,提供多通道同步信号采集与频谱分析功能。此外,测试台还配备了10寸触摸屏、PLC智能控制系统和急停按钮,确保操作简便和安全。 适用人群:机械工程专业师生、科研人员以及从事机械故障诊断和维护的技术人员。 使用场景及目标:①用于高校和科研机构的教学和研究,帮助学生和研究人员深入理解机械故障的机理;②为企业提供故障诊断和预防性维护的解决方案,提高设备可靠性和运行效率;③通过模拟真实工况下的故障,进行轴承寿命预测性试验,研究轴承故障机制与轴承载荷、转速、振动、温度之间的关系。 其他说明:测试台结构紧凑,模块化设计,便于移动和维护。它不仅支持多种传感器的安装和数据采集,还提供了丰富的分析软件功能,如FFT频谱分析、轴心轨迹图、小波分析等,支持数据导出和二次开发,适用于各种复杂的研究和应用需求。

    ### 【5G智慧文旅】商业街、水街信息集成方案:5G技术赋能全方位智慧化升级与游客体验优化

    内容概要:本文档详细介绍了XXX5G特色商业街的规划设计方案,旨在通过5G技术与物联网等前沿科技的融合,全方位提升游客体验感和街区运营效率。首先,基础信息系统涵盖综合管理智慧平台、统一结算系统、5G视频智慧安防监控系统等多个子系统,实现多系统协同管理和数据安全保障。其次,特色应用方面,推出5G短信服务、5G智慧机器人、5G无人巡逻车、5G+XR时空走廊、5G+元宇宙体验馆等项目,将尖端科技与深厚文化底蕴巧妙结合,创新文旅体验形式。最后,通过5G高清视频直播与分享、5G+高空文旅等举措,进一步提升水街的影响力和吸引力。 适用人群:本方案适用于文旅项目规划者、商业街运营管理者、信息技术从业者以及对智慧城市建设感兴趣的各界人士。 使用场景及目标:①为商业街提供全面的智慧化升级方案,涵盖基础信息系统和特色应用两大部分;②通过5G技术赋能,实现高效运营管理和沉浸式游客体验;③推动文旅产业创新发展,促进地方经济繁荣和社会进步。 其他说明:该方案不仅关注技术实现,更重视用户体验和服务质量,强调文化传承与科技创新的有机结合,致力于打造具有国际影响力的智慧文旅新地标。

    【更新至2023年】2000-2023年中国气候政策不确定性指数(全国、省、市三个层面)

    【更新至2023年】2000-2023年中国气候政策不确定性指数数据(全国、省、市三个层面) 1.时间:2000-2023年 2.来源:使用人工审计和深度学习算法MacBERT模型,基于中国《人民日报》《光明日报》《经济日报》《环球时报》《科技日报》《中国新闻社》等6家主流报纸中的1,755,826篇文章,构建了2000年1月至2023年12月的中国全国、省份和主要城市层面的CCPU指数。研究框架包括六个部分:数据收集、清洗数据、人工审计、模型构建、指数计算与标准化以及技术验证。 3.范围:中国、省、市三个层次 4.参考文献:Ma, Y. R., Liu, Z., Ma, D., Zhai, P., Guo, K., Zhang, D., & Ji, Q. (2023). A news-based climate policy uncertainty index for China. Scientific Data, 10(1), 881. 5.时间跨度:全国层面:日度、月度、年度;省级层面:月度、年度;地级市层面:月度、年度

    毕设单片机实战项目基于STM32F401和ESP8266的硬件开源物连网平台.zip

    【项目资源】: 单片机项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

    机械工程BTS200轴承寿命预测测试台Bearing Prognostics Simulator:多功能加载与润滑系统设计及应用反映了文档的核心内容

    内容概要:BTS200轴承寿命预测测试台是一款专为研究轴承寿命预测及加速磨损过程设计的实验设备。该设备结构灵活,支持不同尺寸和类型的轴承测试,最大负载可达15000N。测试台采用先进的伺服电缸加载系统,能够在轴向和径向上精确施加载荷,并配备高精度测力传感器和温度监测系统,确保实验数据的准确性。此外,BTS200还拥有油液循环润滑系统,通过油膜减少摩擦和磨损,保持机械部件在适宜的工作温度范围内,延长轴承寿命。Bearing Prognostics Simulator(实验台可通过触控屏操作,支持多速运行(0-3000RPM),并具备过热保护机制,在温度超过150℃时自动停机。BTS200广泛应用于轴承寿命预测、故障机制研究以及剩余寿命预测模型的开发。 适合人群:轴承设计研发人员、机械工程研究人员、高校实验室师生及相关领域工程师。 使用场景及目标:①研究轴承在不同载荷和转速条件下的磨损特性;②开发和验证轴承剩余寿命预测模型;③探索轴承故障机制及其对系统性能的影响;④评估不同润滑方式对轴承寿命的影响。 其他说明:BTS200测试台不仅提供硬件支持,还配备了完整的软件控制系统,包括PLC闭环控制、温度监测反馈模块等,确保实验过程的稳定性和数据的可靠性。此外,设备支持快速安装和拆卸测试轴承,便于实验操作。

    AXI Memory Mapped to PCI Express (PCIe) Gen2 v2.9

    xilinx基于PCIE IP的PCIE Bridge IP操作手册

Global site tag (gtag.js) - Google Analytics