HTML5离线 MVC: 第 2部分

分享于 

15分钟阅读

Web开发

  繁體 雙語

介绍

这是我的HTML5离线MVC文章的第二部分。 这里的目标是创建一个离线运行的iOS web服务。 所以我们已经断开了所有. NET MVC coodies的连接。 但是我们仍然可以保持一个类似的结构。 实际上,我们制作一个可以重用的MVC框架。 本系列文章的这一部分将在我们的控制器之上创建一个模型。

文章布局

  • 创建一个 JavaScript MVC结构
  • 连接并与WebSql数据库进行交互
  • 通过applicationCache把整个东西 offline

实现

在前一篇文章中,我们创建了源代码,以获得简单但有效的router/controller/view 结构。 现在我们需要把重点放在制造模式上。 在前一篇文章的源下载中,我有一个。 这样我就能把 array的联系人。 一个 array 仍然是数据源,并且没有业务在控制器中。

模型可以多种方式进行设计。 但是,本质上,它们都应该具有以下方法:

  • select ( 获取全部)
  • get ( id ) ( 获取这里文件)
  • insert
  • update
  • delete

模式应该包含所有的业务逻辑。 我不会在本例中添加任何内容,但是在实际情况下,这将是一个地方,"不,不允许"。
但数据本身并不是 inside ! 这里我们将创建一个模态结构,可以使数据 inside 为 WebSql,也可以能只是在线的WCF服务。
我们所有的模型都有一个存储对象在它们上面。 这就是真正保存数据的部分。

让我们来看看我们的联系人模型的最终结果。

namespace("Demo.Models", function(NS) {
 //Our simple modelvar Contacts={
 //Tel the CoreModal singleton which fields we've got and what their attributes should be fields: [
 { name: "id", attributes: "INTEGER PRIMARY KEY AUTOINCREMENT"},
 { name: "name"},
 { name: "lastname"},
 { name: "phonenumber"},
 { name: "email" }
 ],
 //Select all select: function(config) {
 //Right now this is to simple were just passing on the success and failure functions,//but this is the model, so if we would have business logic //we would trap the success handler in here first//apply the business logic an than return the success function //that came in through the config objectvar success=config.success;
 var failure=config.failure;
 this.store.select(config);
 },
 //Get one get: function(id, config) {
 var success=config.success;
 var failure=config.failure;
 this.store.get(id, config);
 },
 //add one insert: function(record, config) {
 var success=config.success;
 var failure=config.failure;
 this.store.insert(record, config);
 },
 //update one update: function(id, record, config) {
 var success=config.success;
 var failure=config.failure;
 this.store.update(id, record, config);
 },
 //delete onedelete: function(id, config) {
 this.store.delete(id, config);
 }
 }
 Demo.Models.Contacts=Contacts;
});

如你所见,这是所有异步就绪。 即使我们只是将记录转储在 array 中,我们仍然将应用成功/失败处理程序。 这是因为我们希望控制器和模型总是具有相同的结构。 不管数据是如何存储的。 对于联机 wcf/httprequests和 WebSql,我们需要它是 asynchronised,因此有一个成功/失败回调结构。

让我们看看联系人控制器的一部分,看看我们将如何使用这个模型。

namespace("Demo.Controllers", function(NS) {
 var Contacts=function() {
 var _self=this;
 //tell the parent class which models to prepare, //this is an array of string representations//that match the namespace/objects where you're models reside. _self.models=["Demo.Models.Contacts"];
 Core.apply(_self, Core.Controller.prototype);
 return Core.Controller.apply(_self, arguments);
 };
 Contacts.prototype.index=function() {
 //contacts/indexvar _self=this;
 //if the select succeeds we'll show the datavar selectSuccess=function(data) {
 _self.viewBag.contacts=data;
 _self.view();
 };
 //Ask our model to select all the records _self.models["Contacts"].select({success:selectSuccess});
 }
 Contacts.prototype.contact=function(action, id) {
 //contacts/contact/{id}var _self=this;
 //ask our model to get a single record _self.models["Contacts"].get(id, {
 //We can also code the success function inline success: function(data) {
 //Stick the data in the viewbag _self.viewBag=data[0];
 //Run our view; _self.view();
 }
 });
 }
. . ......

我们如何才能使这项工作工作?

现在看起来很酷,但是我们显然需要一些代码来使它真正工作。

  • 在前一篇文章中,我们使用 Core.Controller 类来保持控制器本身看起来尽可以能简单。 这个类需要有一定的扩展。
  • 我们将需要一个名为 Core.Model的新的Singleton,它将返回模式并创建/查询存储。
  • 我们需要一个存放数据的存储类。

在前一篇文章中,我试图解释并展示尽可能多的源代码。 但是我们还有很长的路要走。 因此,为了获得一些细节,你必须下载源代码。

我将对 Core.Controller 做什么做一个简短的解释。

Core.Controller

我们的联系人控制器中指定我们希望有一个联系人模型。 为了让 Core.Model 单例将该模型作为工作对象返回,需要扩展 Core.Controller 类。
下载源代码后,可以将它的视为构造函数'return 函数in中的一个循环。

//The models that are readyvar readyModels={};//We'll need to know how many models there arevar numberOfModels=_self.models.length;//loop through the modelsfor(var i=0, j=_self.models.length; i <j; i++) {
 //container for the modelvar success=function(name, model) {
 //add the current mode to readyModels readyModels[name]=model;
 //count down, for if we had more than one model//the controllerAction should be ran after all of them are ready//we cannot reference i because this is asynchronised numberOfModels--;
 if(numberOfModels==0) {
 //all the models are ready//replace the string array of models with the ready models _self.models=readyModels;
 //set the modelsReady boolean _self.modelsReady=true;
 //run the controller action _self[controllerAction].apply(_self, callArguments);
 }
 }
 //get the model Core.Model.getModel(_self.models[i], success);
} 

Core.Model

Core.Model 将返回 Core.Controller 请求的模型,并将存储类绑定到模型的顶部。

namespace("Core", function(NS) {
 //Core.Model has the task of binding the models to the controllers//and to hide the database interaction from the models Core.Model={
 //What models that we already create we'd like to prevent doing it again models: {},
 //Return the model to the controller getModel: function(name, callback) {
 //This will get the object out of a string like"Demo.Namespace1.Object1"var obj=Core.getObject(name);
 //We can not namespace our tables in something like WebSql.//This is a concern it's not possible to have//multiple PERSON tables in different namespaces.//Here we cut of the namespace and work just with the classname.//This might be a point where perfection is needed.var shortName=Core.getLastNsPart(name);
 var _callback=function() {
 callback(shortName, obj);
 }
 if(obj!==undefined) {
 if(this.models.hasOwnProperty(shortName)) {
 //We've already got one. So we don't have to make it again. Just do callback _callback();
 }
 else {
 //What type of store do we need to createswitch(obj.type) {
 case"MEMORY":
 obj.store=new Core.Data.MemoryDataStore();
 break;
 case"PERSISTENT":
 //this line is a sneak preview. We'll be adding this in the next article obj.store=new Core.Data.PersistentDataStore();
 break;
 default:
 obj.store=new Core.Data.MemoryDataStore();
 break;
 }
 //Send in the fields specified in the Model so the store can create itself obj.store.create({ name: shortName }, obj.fields, _callback);
 //Remember this model to prevent executing this code more than oncethis.models[shortName]=obj;
 }
 }
 else {
 thrownew Error("Model" + name + " doesn't exist!");
 }
 },
 }
});

数据存储类

Phew,这是个很长的故事。 对象的array。在本文中,我将创建只保存内存中的数据的DataStore 类。 所以它本质上是无用的,但它会让我们很好地了解这种商店需要做什么。
然后,我们可以创建 WebSql 数据存储。 但是由于处理WebSql本身值得一篇文章,我们将把它分解为。

数据存储需要做什么?

  • create
  • select
  • get
  • insert
  • update
  • delete

我们的类将从我不打算阐述的超类中进行 inherit。

namespace("Core.Data", function(NS) {
 var MemoryDataStore=function() {
 //The name of our storethis.name=null;
 //The fieldsthis.fields=null;
 //The keynamethis.key=null;
 //What holds the actual itemsthis.items=new Array();
 //The key incrementthis.autoincrement=0;
 returnthis;
 };
 MemoryDataStore.prototype=new Core.Data.DataStore();
 MemoryDataStore.prototype.create=function(config, fields, callback) {
 //copy some base informationthis.name=config.name;
 //copy the fieldsthis.fields=fields;
 //We'll need a primary key. We cannot just use the array index.//For it will change when deleting a record.var getPrimaryKey=function(fields) {
 for(var i=0, j=fields.length; i<j; i++) {
 //look for the primary keyif(fields[i].key) {
 //we found itreturn fields[i].name;
 }
 }
 returnnull;
 };
 //Get the key field.this.key=getPrimaryKey(fields);
 //the primary key is important, we cannot just use the array index, //because that will change//when a entry is deletedif(this.key==null) {
 thrownew Error("No primary key found for :" + this.name);
 }
 //do a callback callback();
 };
 MemoryDataStore.prototype.select=function(config) {
 //Since this is just an array it'll be rather simple config.success(this.items);
 };
 MemoryDataStore.prototype.get=function(id, config) {
 //gets a record with the primary key idvar _self=this;
 var record=null;
 var getRecord=function(id) {
 for(var i=0, j=_self.items.length; i<j; i++) {
 if(_self.items[i][_self.key]==id) {
 return _self.items[i];
 }
 }
 returnnull;
 }
 record=getRecord(id);
 if(record==null) {
 config.failure("Record not found!");
 }
 else {
 config.success([record]);
 }
 };
 MemoryDataStore.prototype.insert=function(record, config) {
 //Inserts recordthis.autoincrement++;
 record[this.key]=this.autoincrement;
 this.items[this.items.length]=record;
 //We will return the record in case the model needs to know what id we gave it. config.success(record);
 };
 MemoryDataStore.prototype.update=function(id, record, config) {
 //Updates a recordvar _self=this;
 var index=null;
 var getIndex=function(id) {
 //Find the record with primary key idfor(var i=0, j=_self.items.length; i<j; i++) {
 if(_self.items[i][_self.key]==id) {
 return i;
 }
 }
 return -1;
 }
 index=getIndex(id);
 if(index==-1) {
 config.failure("Record not found!");
 }
 else {
 this.items[index]=record;
 config.success();
 }
 };
 MemoryDataStore.prototype.delete=function(id, config) {
 //Deletes a recordvar _self=this;
 var index=null;
 var getIndex=function(id) {
 //Find the record with primary key idfor(var i=0, j=_self.items.length; i<j; i++) {
 if(_self.items[i][_self.key]==id) {
 return i;
 }
 }
 return -1;
 }
 index=getIndex(id);
 if(index==-1) {
 config.failure("Record not found!");
 }
 else {
 //Delete the actual recordthis.items.splice(index, 1);
 config.success();
 }
 };
 NS["MemoryDataStore"]=MemoryDataStore;
}); 

下载内容中的内容?

这是我们迄今为止所创建的一个演示实现。
它将拥有资产/js 文件夹中的所有核心类。

  • 资产
    • CSS
    • js
      • 核心层
        • 数据
          • core.data.datastore.js
          • core.data.memorydatastore.js
        • core.controller.js
        • core.js
        • core.model.js
        • core.router.js
  • 控制器
    • home.js
    • contacts.js
  • 型号
    • contacts.model.js
  • 视图
    • 主页
      • index.html
    • 联系人
      • addform.html
      • contact.html
      • editform.html
      • index.html

结束语

我还希望有人在那里挂着。 这已经成了一个。 但是如果完成了,我们将有一个简单的小框架,它很容易扩展和实现。 我可能会通过一个关于如何使用这个系列的文档来结束这个系列。 但是这个系列是关于我如何。 下一篇文章将重点介绍在WebSql之上创建一个持久数据存储。


PAR  Html5  离线