Permalink
Fetching contributors…
Cannot retrieve contributors at this time
179 lines (125 sloc) 6.69 KB

在《从这里开始》中介绍了如何使用Clouda开发“Hello World”,现在我们真正使用Clouda开发一个App---"留言大厅"。

首先预览一下"留言大厅"

在"留言大厅"这个应用中,用户可以在这里留言,也可以看到别人的留言

因为需要存储留言,所以在正式开始之前我们需要先安装MongoDB,并在127.0.0.1的27017端口上启动(此地址可在app/server_config/database.js中进行配置),MongoDB是我们依赖的数据库,在以后各种应用中都会经常用到。

###(1)在"app/model/"下创建message.js,输入以下代码:

  • message.js

      Model.message = function(exports){	
      	exports.config = {		
      		fields : [
      			{name: 'content', type: 'text'},
      			{name: 'time', type: 'datetime',defaultValue: 'now()'}
      		]
      	};
      };
    

    可以看到我们刚刚创建了一个包含content和time两个字段的Model,并取名为message,关于Model在下一篇文档中会做专门的说明。

###(2)修改“app/model/package.js”

  • package.js

      sumeru.packages(
      	'message.js'
      );
    

    如我们在上一篇文档中做过的一样,在model/package.js中添加刚刚新增的文件。

###(3)在"app/publish/"下创建pub-message.js,输入以下代码

  • pub-message.js

      module.exports = function(fw){
      	fw.publish('message', 'pub-message', function(callback){
      		var collection = this;
      		collection.find({}, {}, function(err, items){
      			callback(items);
       		});
      	});   
      }
    

    pub-message.js描述了Server将什么类型的数据发布到客服端,在上面的代码中,我们通过publish查询了message model的全部数据,并使用callback将他们发布给客户端,关于publish在下一篇文档中会做专门介绍。

(4) 在"app/controller/"下创建hall.js

  • hall.js

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

    我们在上一篇文档中已经看到过router,sumeru.router.add()作用是添加一个URL(其路径部分)与Controller的映射关系,关于router在下一篇文档中会做专门说明。

      App.hall = sumeru.controller.create(function(env, session){
      	var getMsgs = function(){       
      		session.messages = env.subscribe('pub-message', function(msgCollection){
      			//manipulate synced collection and bind it to serveral view blocks.
                  session.bind('message-hall', {
                  	data    :   msgCollection.find(),
                  });              
    
              });
      	};		
      	//onload is respond for handle all data subscription
      	env.onload = function(){            
      		return [getMsgs];            
      	};
    

    大家可以看到在这里多了一个env.onload(),这是Controller的第一个时态,Controller中需要使用的数据都在这个时态中加载,我们先在这里添加上面的代码,关于env.onload()方法会在下一篇文档中做专门介绍。

      	//sceneRender is respond for handle view render and transition
      	env.onrender = function(doRender){
      		doRender('hall', ['push', 'left']);
      	};
    

    在上一篇文档中我们已经见过env.onrender(),这是Controller的第二个时态,负责对View(视图)的渲染,关于该时态在后续会做专门说明。

      	//onready is respond for event binding and data manipulate
      	env.onready = function(){			
      		session.event('message-hall', function(){     
      			var messageubmitButton = document.getElementById('messageSubmit');
      			var clearHistoryButton = document.getElementById('clearHistory');
           		messageubmitButton.addEventListener('click', submitMessage); 
           		clearHistoryButton.addEventListener('click',clearHistory);                             
              });
      	};
    

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

    可以看到,我们使用了submitMessage()和clearHistory()两个还没有定义的方法,下面我们来实现它们。

      	var submitMessage = function(){
      		var input = document.getElementById('messageInput'),
              	inputVal = input.value.trim();		
             	if (inputVal == '') {
                 return false; 
             	};
             	session.messages.add({
                 content : inputVal,         
             	});
             	session.messages.save();
             	input.value = '';          
      	};
    

    在submitMessage()中我们使用了session.message.add()和session.message.save(),.add()用于在collection中新增一个Model。.save()是用于将collection的修改保存到Server,在通常情况下,调用.save()方法会自动触发对应视图block的更新。

    从这里可以看出,Clouda设计的核心是面向数据的,当数据发生改变时Clouda会自动更新与该数据有关联的视图block,我们称之为"随动反馈",这是Clouda的一个重要特性。

      	var clearHistory = function(){
      		session.messages.destroy();
      		session.messages.save();
      	}		
      });
    

    同.add()的使用方法类似,.destroy()作用是将collection中的数据全部清空,数据清空后同样我们调用.save()根据数据的变化重新渲染与该数据关联视图block。

###(5)修改"app/controller/package.js"

  • pacakge.js

      sumeru.packages(
      	'hall.js'
      );
    

如前面一样,在controller/package.js中添加刚刚新增的文件。

###(6)在"app/view/"下创建hall.html

  • hall.html

      <block tpl-id="message-hall">
      	<style>
      		button{width:100px; height:40px;}
      		#content{width:360px;height:300px;margin-top:10px;}
      	</style>	
      	<div align="center">
      		<h1>Clouda message Hall</h1>
       		<input style="height:40px; width:260px;padding-left: 5px;" id="messageInput" placeholder="Say Something Now:"/>
         		<button id="messageSubmit">submit</button> <br/>
      		<textarea readonly="readonly" id="content">
      		    {{#each data}}
      		        {{this.content}}
                  {{/each}}
      		</textarea><br/>		
      		<button id="clearHistory">clear history</button> 	
      	</div>
      </block>
    

    与上一篇文档中我们看到的View不同,这次hall.html中多了"{{this.content}}",这是插入模板渲染所需的数据变量,Clouda使用handlebars组件作为模板引擎,关于handlebars语法请查看handlebars官网。

至此,App代码部分已经完成。

(7)运行"留言大厅"

启动MongoDB

sudo ./mongod -dbpath ../data/db

重新启动Clouda

sumeru start

在浏览器中输入"localhost:8080/debug.html/hall"运行"留言大厅"。