CLouda相关结构详解

移动开发
Clouda是简单,可依赖的实时Javascript框架。对一个想开发移动webapp的开发者来说,可以使用clouda开发框架,实现一个功能和体验与native app齐平的轻应用。

Publish

Clouda使用PubSub模型描述数据的传输,其中,publish是发布数据的方法,其运行在Server上,每一个publish文件均需要放置在publish/。

  1. module.exports = function(sumeru){      
  2. sumeru.publish(modelName, publishName, function(callback){       
  3. }); } 

可以看到在sumeru.publish()中有三个参数,modelNamepublishName和一个匿名方法function(callback){},下面详细介绍这些参数的作用。

  • modelName:

    被发布数据所属的Model名称

  • publishName:

    所定义的Publish的唯一名称,在一个App内全局唯一,该参数与Controller中subscribe()成对使用。

  • function(callback){}

    描述数据发布规则的自定义函数,在这里定义被发布数据所需要符合的条件。自定义函数自身也可接受由subcribe()传入的参数,如:。

    • function(arg1,arg2,...,callback){}

      其中arg1, arg2为传入参数,传入参数的数量不限,但需要与对应的subscribe()中所传递的参数数量一致。

Subscribe

与sumeru.publish()相对应,我们在Controller中使用env.subscribe()订阅被发布的数据。其中env是Controller中很重要的一个内置对象,稍后我们还会多次见到。

env.subscribe(publishName, function(collection){  });
  • publishName:

    所定义的Publish的唯一名称,在一个App内全局唯一,该参数与sumeru.publish(modelName, publishName,function(callback))中的publishName名称需要保持一致。

  • function(collection)

    Subscribe成功获得数据时,被调用的响应方法。通常,我们主要在其中完成将订阅得到的数据与视图进行绑定(bind)的工作。

    • collection:

      订阅获得的数据Collection对象

如果需要向Publish传递参数(在上一节的最后我们曾经提到),则使用如下形式。

 env.subscribe(publishName,arg1, arg2, ..., function(collection){});

arg1,arg2...等任意数量的参数会被传入sumeru.publish()对应的function(arg1,arg2,...,callback)中。

一个Pub/Sub实例

现有一个学生信息的Model(student),假设Controller希望获取全班同学的信息,我们使用Publish/Subscribe方式实现如下:

  • Publish

    1. module.exports = function(sumeru){      
    2. sumeru.publish('student''pub-allStudents'function(callback){         
    3.  var collection = this;          
    4.  collection.find({}, function(err, items){             
    5.  callback(items);        
    6.   });     
    7.  });            
    8.  } 
  • Subscribe

    env.subscribe("pub-allStudents", function(studentCollection){  });     

假设我们在这个基础上加一个条件限制,现在只希望获取年龄大于18岁同学的信息。

  • Publish

    1. module.exports = function(sumeru){      
    2. sumeru.publish('student''pub-adultStudents'function(callback){         
    3.  var collection = this;           
    4. collection.find({"age":                                       
    5. {$gt:18}                          },  
    6. function(err, items){             
    7.  callback(items);          
    8. });     
    9.  });            
    10.  } 

    大家可以看到我们使用了{"age":{$gt:18}}的方式表达了“年龄大于age”的约束要求。

    相似的,“年龄小于18”的表达方式如下:

    {"age":     {$lt:18} }

    “大于min且小于max”的表达方式如下:

    {"age":     {$gt:min},     {$lt:max} }

    支持的操作符如下:

    操作符 含义
    $gt 大于
    $lt 小于

    对应的Subscribe如下

  • Subscribe

    env.subscribe("pub-adultStudents",function(studentCollection){  }); 

我们在上面的方式上再加一个条件,现在需要大于18岁男生或者女生的信息,性别由Subscribe来决定,如何实现呢?

  • Publish

    1. module.exports = function(sumeru){      
    2. sumeru.publish('student''pub-adultStudentsWithGender'function(gender,callback){         
    3.  var collection = this;           
    4. collection.find({"age":{$gt:18},                            
    5.  "gender": gender                          },  
    6. function(err, items){              
    7. callback(items);          
    8. });      
    9. });             

    在这里可以看出所发布的学生的性别,是由Subscribe决定的。这样来看,一个Publish,可以通过不同的参数,为多个Subscribe服务。从这个角度来讲,Publish有点类似于OO语言中的Class的概念,可以理解为Publish发布的是一类数据。

    类似的,对应的Subscribe调用如下:

  • Subscribe

    env.subscribe("pub-adultStudentsWithGender","male",function(msgCollection){  });

external

Clouda提供了三方数据同步的方法,用来满足从第三方网站/第三方接口获取和同步数据的需求。下面将通过一个例子来说明一次三方数据同步的过程。

1. 定义第三方数据Model

在抓取第三方数据之前,先定义一个三方数据的Model用于描述抓取后数据的结构,在app/model目录下定义model,三方model定义与普通model定义完全一致

  1. Model.student = function(exports){      
  2. exports.config = {          
  3. fields : [              
  4. { name : 'name', type : 'text'},              
  5. { name : 'age', type : 'int', defaultValue : 0}          
  6. ]      
  7. } } 

2. 指定三方数据来源与解析方法

app/publish/下新增externalConfig.js文件(文件名任意,推荐使用externalConfig.js),用来指定第三方数据来源与解析方法,需要注意必须为抓取回来的数据指定一个唯一标识uniqueColumn

  1. /**  * 获取第三方数据信息,由开发者自定义  */ function runnable(){      
  2. //{Object} config是所有三方publish配置的容器     
  3.  var config = {};       
  4. config['pubext'] = {         
  5.  //{String} uniqueColumn为三方数据唯一标识          
  6. uniqueColumn : "name",           
  7. //{Function} fetchUrl的参数就是订阅时发起的参数,返回值为pubext所抓取的url地址          
  8. fetchUrl : function(/** arg1, arg2, arg3 */){              
  9. return 'http://some.host.com';          
  10. },           
  11. //{Function} resolve方法作用是将抓取回来的原始数据(originData)转化成为符合Model定义的数据(resolved)          
  12. resolve : function(originData){              
  13. var j = JSON.parse(originData);              
  14. var resolved = j;               
  15. return resolved;         
  16.  },           
  17. //{Number} fetchInterval为可选参数,用来指定抓取时间间隔,单位为ms         
  18.  fetchInterval : 60 * 1000,          
  19.  //{Boolean} buffer为可选参数,值为true时表示获取原始Buffer,否则获取原始数据字符串          
  20. buffer : false      
  21. }       
  22. //最后需要声明此模块为归属为'external'     return {          
  23. type : 'external',          
  24. config : config      
  25. }  }  module.exports = runnable; 

3. publish第三方数据

上面制定了第三方数据来源之后,就可以在publish中将其发布出来,注意这里需要使用collection.extfind方法,该方法表示此collection为三方数据,处理数据方式不同。

  1. //与普通的collection.find不同,第三方数据的publish调用collection.extfind方法表示此collection为三方数据  
  2. fw.publish('student''pubext'function(/** arg1, arg2, arg3...*/ callback){     
  3.  var collection = this;      
  4. collection.extfind('pubext'/** arg1, arg2, arg3...*/ callback);  }); 

4. 指定三方增/删/改接口以及数据

如想将本地数据修改同步到三方,并且三方提供相应的post接口,可以在app/publish/externalConfig.js文件中,声明三方增/删/改接口以及数据:

较为紧凑的声明方式

声明中:

  • postUrl方法用来指定三方post接口的地址信息, 参数type为增量类型,增量类型为'insert','update','delete'三者之一;

  • prepare方法用来将增量数据转化成为符合三方POST接口要求的post数据,参数type同为增量类型,参数data为增量的实际数据。

    1. /**  *  三方数据POST请求信息,由开发者自定义  */  
    2. function runnable(){       
    3. var config = {}       
    4. config['pubext'] = {          
    5.  /**          * 声明三方POST接口地址          *  
    6. {String} type为'delete', 'insert', 'update'其中之一           
    7. * 如果subscribe时带参数,参数会按照subscribe顺序接在postUrl的参数中          */         
    8.  postUrl : function(type /** arg1, arg2, arg3... */){               
    9. var options = {                 
    10.  host : 'some.host.com',                  
    11. path : '/' + type ,                  
    12. headers: {                      
    13. //在此自定义header内容,clouda默认的 'Content-Type': 'application/x-www-form-urlencoded'                     'Content-Type': ...                 
    14.  }              }               
    15. return options;          },          
    16.  /**          * prepare方法将增量数据转化为符合三方要求的post数据。           
    17. * {String} type为增量操作,值为'delete', 'insert', 'update'其一;           
    18. * {Object} data为增量数据,如:{ name : 'user1', age : 26 }。          */          
    19. prepare : function(type, data){              
    20. var prepareData = {};   
    21. //prepareData为三方post所需的data              
    22. if(type === "delete"){                  
    23. prepareData.name = data.name;             } 
    24. else if(type === "insert"){                  
    25. prepareData.name = data.name;                  
    26. prepareData.age = data.age;             
    27.  }else{                 
    28.  prepareData.name = data.name;                  
    29. prepareData.age = data.age;             }               
    30. return prepareData;          
    31. }     }       
    32. return {          
    33. type : 'external',          
    34. config : config     }  }   
    35. module.exports = runnable; 
较为工整的声明方式

较为工整的声明方式根据type将不同操作区分开来。

声明中:

  • deleteUrlinsertUrlupdateUrl三个方法作用等同于postUrl,返回不同操作下三方接口url信息;

  • onDeleteonInsertonUpdate三个方法作用等同于prepare方法, 返回经过处理,传给三方接口的post数据。

    1. function runnable(){       
    2. var config = {};       
    3. config['pubext'] = {          
    4. //arg1, arg2, arg3是subscribe时输入的参数          
    5. deleteUrl : function(/** arg1, arg2, arg3... */){              
    6. return {                  
    7. host : 'some.host.com',                  
    8. path : '/delete' ,                  
    9. headers: {                      
    10. //在此自定义header内容,clouda默认的 'Content-Type': 'application/x-www-form-urlencoded'                     'Content-Type': ...                 
    11.  }              
    12. }         },           
    13. insertUrl : function(/** arg1, arg2, arg3... */){              
    14. return {                 
    15.  host : 'some.host.com',                  
    16. path : '/insert',                 
    17.  headers: {                      
    18. //在此自定义header内容,clouda默认的 'Content-Type': 'application/x-www-form-urlencoded'                     'Content-Type': ...                  
    19. }              
    20. }         },           
    21. updateUrl : function(/** arg1, arg2, arg3... */){             
    22.  return {                 
    23. host : 'some.host.com',                  
    24. path : '/update',                  
    25. headers: {                      
    26. //在此自定义header内容,clouda默认的 'Content-Type': 'application/x-www-form-urlencoded'                     'Content-Type': ...                 
    27.  }             
    28. }         },           
    29. onInsert : function(data){             
    30.  var prepareData = {};             
    31.  prepareData.name = data.name;              
    32. prepareData.age = data.age;              
    33. return prepareData;         },           
    34. onUpdate : function(data){              
    35. var prepareData = {};              
    36. prepareData.name = data.name;              
    37. prepareData.age = data.age;              
    38. return prepareData;         },           
    39. onDelete : function(data){              
    40. var prepareData = {}              
    41. prepareData.name = data.name;              
    42. return prepareData;         }     }       
    43. return {          
    44. type : 'external',          
    45. config : config      
    46. }  }  module.exports = runnable; 

5. subsribe第三方数据

subscribe方法与普通subscribe无差别,开发者只用关心所订阅的pubName,而不用区分数据来源。

  1. function getExt() {      
  2. session.extStudent = env.subscribe('pubext'function(collection, info){          
  3. session.bind('extBlock', {              
  4. data : collection.find().getData()          
  5. });      
  6. }); } 

sumeru.external.post与sumeru.external.get接口

如果上面的方法不能满足您的需求,Clouda同样提供更底层,更灵活的post和get接口

向第三方发送get请求
var url = "http://some.host.com"; var getCallback = function(data){     console.log(data); } sumeru.external.get(url, getCallback);
向第三方发送post请求

 

  1. var options = {      
  2. host : "some.host.com",      
  3. path : "/insert" }  
  4.  var postData = {      
  5. name : sumeru.utils.randomStr(8),      
  6. age : parseInt( 100 * Math.random()) }   
  7. var postCallback = function(data){      
  8. console.log(data); }   
  9. sumeru.external.post(options, postData, postCallback); 
  10.  
  11. 详细代码和说明请参考《Examples》文档中SpiderNews实例。 

Controller

如果你曾经接触过MVC模型,那么将会很熟悉Controller的概念。在Clouda中,Controller是每个场景的控制器,负责实现App的核心业务逻辑。每一个Controller文件都放在controller/下。

 App.studentList = sumeru.controller.create(function(env, session){   });

使用sumeru.controller.create()创建一个名为studentList的Controller。

在Controller中有两个非常重要的对象env和session,env用来绑定Controller的生命周期方法,session用来绑用户数据,下面详细的介绍这两个对象。

env

env用来绑定Controller的生命周期方法,Controller具有以下几个时态:onload()、onrender()、onready()、onsleep()、onresume()、ondestroy()。

  • onload

    语法:env.onload(){}

    onload()是Controller的第一个时态,Controller中需要使用的数据都在这个时态中加载,我们上面谈到过的subscribe()也多在这个时态中使用,方法如下。

    1. App.studentList = sumeru.controller.create(function(env, session){      
    2. var getAllStudents = function(){          
    3. env.subscribe("pub-allStudents",function(studentCollection){          
    4.  });     };       
    5. env.onload = function(){          
    6. return [getAllStudents];      
    7. };  }); 

    注意:如果您开启了Server端渲染,那么在onload函数中需确保onload中,没有使用前端的js中的变量或函数,比如window,document,Localstorage等

  • onrender

    语法:env.onrender(){}

    当数据获取完成后,这些数据需要显示在视图(View)上,这个过程通过onrender()中的代码来实现,这是Controller的第二个时态,负责完成对视图(View)的渲染和指定转场方式。

    env.onrender = function(doRender){     doRender(viewName,transition); };
    • viewName

      需要渲染的视图(View)名称。

    • transition

      定义视图转场,形式如下:

      ['push', 'left']

      转场方式:我们提供'none', 'push'、'rotate'、'fade'、'shake'五种转场方式

      转场方向:不同的转场方式有不同的转场方向,请参考附录:《API说明文档》

  • onready

    语法:env.onready(){}

    这是Controller的第三个时态,在View渲染完成后,事件绑定、DOM操作等业务逻辑都在该时态中完成;每段逻辑使用session.event包装,从而建立事件与视图block的对应关系。

     env.onready = function(){     session.event(blockID,function(){      });  };
    • blockID

      View中block的id,关于block在接下View中会做详细的介绍。

    • function(){}

      事件绑定、DOM操作等业务逻辑在这里完成。例如有一个View如下:

      <block tpl-id="studentList">     <button id="submit"> </button> </block>

      如何对view中的submit做事件绑定呢?可以通过下面代码实现:

      1. env.onready = function(){      
      2. session.event("studentList",function(){         
      3.  document.getElementById('submit').addEventListener('click', submitMessage);      
      4. });  }; 

    在开发移动终端上的应用时常会使用到很多的手势操作,例如旋转放大拖动等等,为了方便开发者快速的集成这些手势,Clouda中内置了事件和手势库Library.touch,如何使用Library.touch请查看API手册touch部分。

  • redirect

    语法:env.redirect(queryPath,paramMap,isforce)

    一个Controller跳转到另一个Controller

        env.redirect('/studentList',{'class':'101'});
    • queryPath

      router中pattern的值

    • paramMap

      需要向跳转Controller传递的参数
    • isforce

      是否强制生成一个全新的Controller实例。

  • arguments

    语法:env.arguments[pattren,params1,...,paramsN]

    使用该方法可以获取URL中参数,例如:

    URLhttp://test.duapp.com/sourcepage/params1/params2/.../paramsN

    Controller中定义router:

    1. sumeru.router.add(     {          
    2. pattern: '/sourcepage',          
    3. action: 'App.SourceController'     
    4.  } ); 

    那么在该Controller中就可以使用env.arguments[1]到env.arguments[N]获取对应的参数。

session

如果您有数据需要绑定到Controller,可以使用session中的方法:

  • get

    语法:session.get(key)

    获取session中“key”的值

  • set

    语法:session.set(keyvalue)

    设置session中“key”的值

  • commit

    语法:session.commit()

    当你更新了session的数据时,需要根据新的session的数据更新UI是,您可以使用session.commit()就会触发数据对应视图block的更新。

Controller接收URL中的参数

  • 使用env.redirect()方法

    当一个Controller(起始Controller)跳转到另一个Controller(目标Controller)时,可以使用env.redirect()方法来实现参数的传递,方法如下:

    • 使用paramMap传递参数

      • 在起始Controller中

        env.redirect(queryPath ,paramMap);

        第一个queryPath: 目标Controller在router中“pattern”的值;

        paramMap:需要传递的参数

      • 目标Controller中使用session.get()方法获取参数

        sumeru.controller.create(function(env, session){      session.get();  });
    • 使用URL路径部分传递参数

      • 在起始Controller中

        env.redirect(queryPath/params1/params2);
      • 目标Controller中使用session.get()方法获取参数

        1. sumeru.controller.create(function(env, session){      
        2.  params1 = env.arguments[1];     
        3.  params2 = env.arguments[2]; }); 
    • 实例

      • SourceController.js

        1. sumeru.router.add(     {          
        2. pattern: '/sourcepage',          
        3. action: 'App.SourceController'      
        4. } );   
        5. App.SourceController = sumeru.controller.create(function(env, session){         
        6.  env.redirect('/destinationpage/100/200',{'a':100,'b':200}); }); 
      • DestinationController.js

        1. sumeru.router.add(     {         
        2.  pattern: '/destinationpage',          
        3. action: 'App.DestinationController'      
        4. } );   
        5. App.DestinationController = sumeru.controller.create(function(env, session){      
        6. console.log(session.get('a'));      
        7. console.log(session.get('b'));      
        8. console.log(env.arguments[1]);      
        9. console.log(env.arguments[2]); }); 

    跳转后的URL为:http://localhost:8080/debug.html/destinationpage/200/100?a=100&b=200&

    开发者也可按照上面的URl格式来拼接一个带参数的URL,关于URL我们会在本文档URL说明部分做详细的说明。

#p#

Model

我们使用Model来定义App的数据模型,例如在model/下创建一个student.js

 Model.student = function(exports){       };

在"student"中添加"studentName"、"age"和"gender"三个字段:

  1.  Model.student = function(exports){      
  2. exports.config = {          
  3. fields: [              
  4. {name : 'studentName', type: 'string'},              
  5. {name : 'age',         type: 'int'},              
  6. {name : 'gender',      type: 'string'}          
  7. ]     };  }; 
  • name

    字段的名称

  • type

    字段的数据类型,包括"int"、"datetime"、"string"、"object"、"array"、"model"、"collection"。

除以上两种,常用的属性还包括:

  • defaultValue

    字段的默认值

    {name: 'gender', type: 'string', defaultValue: 'male'}

    若不提供"gender"值时,则字段的默认值为"male"。

    再看一个时间的例子:

    {name: 'time', type: 'datetime', defaultValue: 'now()'}

    若不提供"time"值时,则字段的默认值为当前服务器时间。

  • validation

    字段的验证,validation包括以下方法:

    • length[min,max]

      字段值得长度在min-max的范围。

    • mobilephone

      必须为手机号码格式,长度为11位且必须为数字

    • required

      字段值不能为空

    • number

      字段值必须为数字

    • unique

      字段值必须唯一

    更多内置验证方法和自定义验证方法,请参考附录:《API说明文档》

  • model

    当type值为model和collection时,表示该字段包含一个指向其他model的1:1 或 1:n 的关系。 此时,需同时提供model字段以声明指向的model对象。

    {name: 'classes', type: 'model', model: 'Model.classes'}

Collection

Collection是Model的集合,我们之前曾使用过的subscribe()返回的结果集即是Collection。

session.studentCollection = env.subscribe("pub-allStudents",function(myCollection){  });

session.studentCollection是返回的Collection。可对数据集进行“增、删、查、改”的操作:

  • add

    语法:add()

    使用add()在Collection中添加一行数据。

    1. session.studentCollection.add({      
    2. studentName: 'John',      
    3. age: 18,      
    4. gender:"male"                    
    5.  }); 
  • save

    语法:save()

    save()是用于将collection的修改保存到Server,在通常情况下,调用save()方法会自动触发对应视图block的更新。

    session.studentCollection.save();
  • find

    语法:find()

    使用find()查询Collection中符合条件的所有Model。

    session.studentCollection.find();

    使用条件查询时,例如查找gender为“male”的Model;

    session.studentCollection.find({gender:'male'});
  • destroy

    语法: destroy()

    使用destroy()从Collection中移除数据,

    session.studentCollection.destroy();

    使用条件删除时,例如删除gender为“male”的Model:

    session.studentCollection.destroy({gender:'male'});

更多Collection API 请参考附录:《API说明文档》

View

在上一篇文档中我们介绍过Clouda的一个重要特性“随动反馈”,那么“随动反馈”是怎么实现的呢?

Controller的onload()时态里,每一个session.bind的BLOCKID,都对应View中的一个"block"标签。 Clouda使用Block为粒度来标记当数据发生变化时View中需要更新的部分,使用handlebars组件作为模板引擎。

在view中使用“block”标签定义需要更新部分,并定义tpl-id

  1. <block tpl-id="studentList">      
  2. <p>           
  3. {{#each data}}              
  4. {{this.studentName}}          
  5. {{/each}}                 
  6. </p>  
  7. </block> 

view中的data来源于Controller中onload()时态的session.bind()

env.subscribe("pub-allStudents",function(studentCollection){     session.bind('studentList', {         data : studentCollection.find(),     }); }); 

通过以上方法,我们就建立了一个基本的"随动反馈"单位,当订阅的数据发生变化时,View中对应的部分将自动更新。

Handlebars的语法非常易用,但为了更快的开发视图代码,Clouda还额外提供了便捷的工具方法

  • foreach

    用于快速遍历一个对象或数组

    语法:{{#foreach}}{{/foreach}}

    用法示例:

    1. <p id="test-foreach-caseB">      
    2. {{#foreach customObj}}          
    3. {{key}} : {{value}}      
    4. {{/foreach}}  
    5. </p> 
  • compare

    比较两个对象

    语法:     {{#compare a operator b}}     {{else}}     {{/compare}}

    可以使用的operator:

    operator
    ==
    ===
    !=
    !==
    <
    <=
    >
    >=
    typeof

    用法示例:

    1. {{#compare a "<" b}}      
    2. a < b {{else}}      
    3. a >= b {{/compare}}   
    4. {{#compare a "typeof" "undefined"}}      
    5. undefined {{/compare}} 

    注意:当省略operator时,系统默认使用操作符 ==:

    {{#compare 1 1}}     1 == 1 {{/compare}}
  • {{$ }}

    在View中直接执行Javascript代码,并将返回结果输出在View中。

    {{$ alert("data.length"); }}

View之间的互相引用

  • {{> viewname}}

    在一个View中引用另一个View。

配置view加载路径

一般情况下将编写的View文件都存放在app/view文件夹下,如果编写的view文件不在app/view文件夹下,我们也提供View文件路径配置的方法,框架会在配置路径先寻找需要的View文件:

sumeru.config.view.set('path', 'path/to/');

则Clouda会在如下目录中加载视图:

app目录/path/to/view/

注意:即使是修改viewpath的情况下,在最内一侧仍然需要有一层view文件夹,如上面路径的最后部分。

Router

Router用于建立URL中pattern与Controller之间的对应关系,添加router的操作通常在Controller文件中定义。

一个Controller可以对应多个URL,一个URL只能对应一个Controller。

  • add

    语法: sumeru.router.add({pattern:'' , action:''});

    使用add()可以在router添加一组pattern与Controller的对于关系,方法如下:

    sumeru.router.add( { pattern: '/studentList', action: 'App.studentList' } );

    • pattern

      URL中pattern部分的值

    • action

      对应Controller的名称

通过add方法在router中添加了URL(其路径部分)和Controller的对应关系,就可以使用 “localhost:8080/debug.html/studentList”运行URL(其路径部分)为"/studentList"对应的 Controller。

同时我们还提供定义默认启动Controller的方法:

  • setDefault

    语法: sumeru.router.setDefault(Controller Name)

实例:

sumeru.router.setDefault('App.studentList');

在Controller中使用setDefault()后,浏览器中输入“localhost:8080/debug.html”就可以启动该Controller,不需要在URL中带路径部分。

这里使用debug.html为调试模式,关于调试模式在“URL说明”部分会作详细介绍。

为了满足加快view渲染速度的需求,Clouda加入了Server渲染的功能。server渲染默认是开启的,如果想单独禁止某个View在Server渲染,可在Router中通过server渲染开关来禁止server渲染。

  1. sumeru.router.add({      
  2. pattern:'/test',      
  3. action : 'App.unittest',      
  4. server_render:false  
  5. }) 

router的外部处理器

如果您使用backbone等第三方框架,或是存在已有代码根据URL的变化执行一些逻辑,那么这些需求,都可以通过注册一个router的外部处理器使其保持正常工作。

一个外部处理器的写法:

var processor = function(path){     //do something     return true; }

添加一个外部处理器:

sumeru.router.externalProcessor.add(processor);

添加一个backbone的外部处理器的例子:

sumeru.router.externalProcessor.add(Backbone.Router.extend());

server_config

当您有一些配置文件以及敏感信息不想被下发到客户端时,您可以将这些文件放在server_config文件夹下。

例如在应用中使用了一些私密的ip而不想把ip下发到客服端导致安全问题,可将ip的信息配置文件放在server_config文件夹下,方法如下:

在server_config文件夹下新建ip_config.js

sumeru.config({     secret_ip: **.**.**.** });

并在server_config/package.js添加文件名:

sumeru.package({    "ip_config.js" });

这样ip_config.js文件不会被下发到客户端上,如果需要获取secret_ip的值可在server上使用下面方法:

sumeru.config.get("secret_ip");

在server_config文件夹下默认存放的文件为Clouda配置文件,包括:

  • bae.js

  • database.js

  • site_url.js

  • server_library.js

注意:上面四个文件为Clouda保留文件,开发者不可以在server_config文件夹下创建同名的文件,也不可以在上述四个文件中添加内容

Library

有的时候我们会遇到这样的麻烦,比如Model中有一个数据类型为“date”的时间字段,而在View上我想显示的是年,我们可以在View使用{{$ }}方法嵌入JavaScript来实现。

虽然这种方法可以实现,但是不易代码管理,我们需要一个library库的管理机制来解决这个问题,例如你可以将这个时间格式化函数存放在library/下:

  • /library/getTime.js

    1. Library.timeUtils = sumeru.Library.create(function(exports){          
    2. exports.formatDate = function(time){          
    3. return time.getFullYear();      
    4. };  }); 
  • /view/student.html

    1. <block tpl-id="studentList">       
    2. <p>           
    3. {{#each data}}              
    4. {{$Library.timeUtils.formatDate(this.time)}}         
    5. {{/each}}                 
    6. </p>   
    7. </block> 

也可以在controller中调用library库,例如:

  • /controller/student.js

    session.bind('studentList', {     year : Library.timeUtils.formatDate(time) });

通常,在onload,onrender和视图文件中使用到的新增加的Library或Handlebars Helpers,都需要同时配置在server_config/server_library中,方法如下:

打开server_config/server_library.js

sumeru.packages('../library/handlbars_helper.js');
责任编辑:张叶青
相关推荐

2013-10-30 22:50:30

Clouda结构

2013-10-30 17:34:22

Clouda安装使用

2013-10-30 22:41:23

Clouda环境

2013-10-31 10:57:10

CloudaManifest

2013-10-31 10:59:41

Clouda使用

2013-10-31 11:04:03

Cloudapackage.js

2013-10-31 22:53:58

Clouda程序

2014-05-15 09:43:11

CloudaMobile WebANodejs

2020-08-21 10:05:22

Linux系统结构内核

2011-03-08 11:13:52

proftpd结构

2009-09-27 13:57:19

Hibernate树形

2010-11-15 11:58:02

Oracle物理结构

2013-11-04 17:38:09

Clouda百度

2010-05-24 09:11:06

SVN版本库

2019-04-02 08:36:12

2010-01-05 18:09:07

.NET Framew

2009-12-29 17:25:36

Silverlight

2009-12-28 16:00:36

WPF样式继承

2010-03-01 09:19:10

WCF编码规范

2010-01-26 18:00:07

Android屏幕元素
点赞
收藏

51CTO技术栈公众号