说明:本文是按照compound官网文档,学习总结翻译而来。
1. 使用命令创建一个项目。
$compound init 项目名称
2. 在开发模式下,我们修改model controller view 等它都会自动更新,但是修改routes 或者 scheme我们就必须重启服务。或者可以使用node-dev命令(npm install node-dev first),在每次修改后都会自动重启服务。
3. 使用compoundroutes 可以查看所有提供给应用程序的有效路由
4. Compoundjs有两种控制器。
(1) evalController(文件名以_controller结尾):这种控制器提供方便的接口,以较少的代码完成表示。但是它调试困难,缺少常见的特性例如继承,meta-programming(不知该如何翻译)
Example of evalcontroller: app/controllers/car_controller.js:
load('essentials');// load parent controller
before(functionthink() {
// think for 1 second before acceperate
setTimeout(function() {
next();
});
}, {only:'accelerate'});
action('accelerate',function() {
send(++this.speed);
});
action('brake',function() {
send(--this.speed);
});
(2) noevalcontroller(文件不是以_controller结尾)方便调试,支持继承,meta-programming等
Example of noevalcontroller: app/controllers/car.js:
module.exports =CarController;
// load parentcontroller
var Essentials =require('./essentials');
functionCarController(init) {
// call parent constructor
Essentials.call(this, init);
init.before(function think(c) {
// think for 1 second before accelerate
setTimeout(function() {
c.next();
});
}, {only: 'accelerate'});
}
// setupinheritance
require('util').inherits(CarController,Essentials);
CarController.prototype.accelerate= function(c) {
c.send(++this.speed);
};
CarController.prototype.brake= function(c) {
c.send(++this.speed);
};
说明:二者主要的区别在于:使用控制器的上下文(环境)。
(1) 如果是eval,它可能仅仅是调用控制器环境成员作为全局变量:next,req,res,send,render或者其它。而 noeval,每一个action或者hook接收上下文(环境)对象作为第一个参数,所有的环境特性适应于这个对象。
(2) 使用eval调用action(name,fn)方法。第一个参数是可选的。调用hook使用before,after方法。使用noeval。Controller file 应该export 构造方法。Actions 作为构造函数的原型方法。控制器构造函数接收init对象。它可以识别当前的控制器。定义hook调用init对象上的before和after方法,传递给构造函数。
(3) 控制器上下文环境有以下成员:req, res, body(如果是get方法它是空。)
(上面三个是控制器成员,接下来是一些控制器方法。)
5. output 方法(每一个action都要有一个输出方法。)控制器output方法。
(1) render(); 接收0,1,或者2个参数。第一个参数读取哪个一个view.如果要给view传递变量,可以使用.render({title:’Hello’});
eg:
PostsController.prototype.update = function update(c) {
this.title = 'Edit post';
c.render('edit');
};
(2) send(smth):给客户端发送text,状态码,json对象等。它在调试的时候非常有用,或者是你不想给一个页面读取沉重的模板,仅是想发送文本,json对象。
Eg:
c.send(403); c.send(‘hello’); c.send({hello:’world’});
(3) redirect(location):仅需设置状态码和locationheader。客户端就可以跳转到另外一个location.
Eg:
redirect(‘/’); //路由跳转
redirect(‘http://example.com’); //跳转到另外一个host
(4) header() 为客户端设置header
(5) flash(type,message): 显示flash信息。Flash函数在session中存储信息,使之稍后显示。
Eg:
PostsController.prototype.create = functioncreate(c) {
c.Post.create(req.body, function (err) {
if (err) {
c.flash('error', 'Error while post creation');
c.render('new', {post: req.body});
} else {
c.flash('info', 'Post has been successfully created');
c.redirect(c.pathTo.posts);
}
});
});
6. 控制器流控制方法。
(1) before([name,]hook[,params]): 在任何action前面使用hook,name参数是可选的当hook是有名函数。
Eg1
{ only:['actionName', 'actionName2'] }
{ except:'anotherActionName' }
说明:第一个配置将运行hook,only 为actionName actionName2 action。第二个配置将在每一个action之前运行hook 除了 'anotherActionName'。
Eg2:
Fragmentof app/controllers/checkout.js:
function CheckoutController(init) {
init.before(userRequired, { only: 'order' });
init.before(prepareBasket, { except: 'order' });
init.before(loadProducts, { only: ['products', 'featuredProducts'] });
}
CheckoutController.prototype.products =function(c) { ... };
CheckoutController.prototype.featuredProducts= function(c) { ... };
CheckoutController.prototype.order =function(c) { ... };
CheckoutController.prototype.basket =function(c) { ... };
function userRequired(c) { c.next() }
function prepareBasket(c) { c.next() }
function loadProducts(c) { c.next() }
注意:
(1)before方法应当调用全局 next()方法,这样就可以将控制传递给调用链条中的下一个方法。
(2) after([name,]hool[,params]) 在action后面调用方法。
(3) skipBefore(name,params)
(4) skipAfter(name,params)
(5) next(err)
7. 仅在eval中的方法。
(1) eval有一些方法允许控制器之间共享代码。(noeval)不需要这个,因为它可以使用require和继承
(2) load: 加载另一个控制器,使用它其中的方法。
(3) use: 得到另一个控制器中已经定义的方法,在使用load加载之后。
(4) publish:允许方法被其他控制器使用。
Eg:
Fragment of app/controllers/application_controller.js:
publish('requireUser', requireUser);
function requireUser () {
// ...
}
Fragmentof app/controllers/products_controller.js:
load('application'); // note that_controller siffix omitted
before(use('userRequired'), { only: 'products'});
8. 扩展控制器上下文环境,使用compound.controllerExtensions对象。这个对象的方法将混合在每一个控制器上下文环境。
Eg:
compound.controllerExtensions.socketSend =function(arg) {
socketIO.send(arg);
};
Then it will be possible tocall socket('hello') in eval controller, andc.socket('hello') innoeval controller.
9. view
lists_controller.js中index action下,使用render(); 则默认调用的view是:
./app/views/lists/index.ejs
10. layout
(1)如果render aview 不带有layout 我们可以使用{layout:false}作为render()的参数开设置,也可以使用$this->layout = false;在controller中设置。
(2)如果使用layout可以用c.layout(‘’);指定想要用的layout