使用的入门教程是《Node.js开发指南》,其中使用的express版本较老。从安装开始就出现问题。到第五章的时候,基本没法按书中走下去了。这里按新的express版本做试验。
安装express
npm安装express,-g指令进行全局安装:
# npm install -g express
安装express-generator包
在很久很久以前,那时候express的版本还不到4.0,那时候安装完express后就可以通过express --help
试用express命令了。一切如同书中所说的那么美好。但如果现在你还照着书上说的那么做,控制台会告诉你没有express
这种东西,直接把你雷的外焦里嫩。
历史发展到现在,那一切已经不好使了。想要使用express
指令,实际上还需要安装一个叫express-generator的东西。
# npm install -g express-generator
Okey,现在可以愉快的使用express指令了。
建立app
千万别以为可以正常的使用express指令就可以顺利的继续照着《Node.js开发指南》学习了,狗血的情节不止出现在电影里,还有程序员的屏幕里。
- 首先是你会发现创建好的app需要的依赖比书的多了不止一倍;
- 第二你又发现书中的
express -t ejs microblog
指令根本不好使,创建出来的模版引擎照样是jade
。 - 第三你最后还发现了用
$node app.js
指令后,啥事也没发生。
好吧,我们一件一件来。关于现在用express创建的app的依赖,现在是多了很多东西,其实是一个真实工业应用所具备的基础,以前的express没有那么成熟,所以没有,但现在它会自动的创建出来,我们可以先无视它,反正多上这些也不会让你的硬盘爆炸。
如果要使用ejs代替jade,现在不需要用-t ejs
了,如果你查下express --help
,它会告诉你直接加上-e
就好,就是这样:$express -e microblog
。
最后,要让你的app运行起来,目前以我了解到的可以使用debug的模式,这样:$ cd microblog
然后这样:$ debug=microblog ./bin/www
。
这时再打开ie,输入http://127.0.0.1:3000
,你便可以看见亲切的Welcome to Express
啦!
好啦。现在项目创建出来啦,浏览器也可以打开啦,接着下去,是不是可以继续照着书做呢?嗯……,我觉得吧还是算了吧,书里解说的和生成的代码都是两回事,还不如到 http://www.expressjs.com.cn上去看看😂
文件结构
好吧,为了做事不永远只做一半,咱还是继续跟着书继续往下折腾。人生就是不停的折腾才有意义对吧。
首先咱先看看创建出来的目录结构:
.
├── app.js
├── bin
│ └── www
├── node_modules
│ ├── body-parser
│ ├── cookie-parser
│ ├── debug
│ ├── ejs
│ ├── express
│ ├── morgan
│ └── serve-favicon
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.ejs
└── index.ejs
-
bin/www 文件简要
首先程序是从 bin/www 这个文件执行起的。如果你的电脑是linux或者mac,可以在控制台中查看
file bin/www
,它会跟你说:“bin/www: a node script text executable”,换成咱的话就是:这是个可执行的node脚本。什么叫可执行的node脚本呢?通常我们如果要执行一个node.js的文件,会采用这种形式:
$ node hello.js
,但如果是一个可执行的脚本,则无须使用node
命令,直接这样:./hello.js
就可以了。如果你要让你的js文件也变成可执行文件,那只需作两步工作(windows下无效哦……赶紧买苹果吧,要不换linux?):1. 在hello.js 文件的开头加上 `#!/usr/bin/env node`, 2. 在终端中给hello.js加上可执行权限`$ chmod +x hello.js`。 3. 然后你就可以愉快的`$ ./hello.js`啦。
小小的提醒下,如果把默认的
#!/usr/bin/env node
改为#!/usr/bin/env supervisor
,那启动后每次改代码可以不用手工重新启动服务哦。—— 猫式跑题了——
咱回到 bin/www 文件,拜读一下程序生成的这段代码:
/** * Create HTTP server. */ var server = http.createServer(app); /** * Listen on provided port, on all network interfaces. */ server.listen(port); server.on('error', onError); server.on('listening', onListening);
很明显嘛,原来端口是在这里指定的,server也是在这里启动的。但是有关server启动的因素,却是由app这个对象塑造啦。这个app在文件开头的时候已经指定好
var app = require('../app');
,对照这目录结构,原来就是根目录下的app.js文件。 -
app.js 文件简要
仔细阅读下 app.js,第11行,发现有个var app = express();
,哈,传说中的 express 对象原来就在这。bin/www 中http.createServer(app)原来就是通过这个express来构造的。
往下看,其它的先不管,先看这几段话:// 视图引擎设置(视图放这里./views下) app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // ... ... // 配置静态文件服务器(客户端js、css文件放这里,./public下): app.use(express.static(path.join(__dirname, 'public'))); // 路由设置(路由放这里 ./routes下) app.use('/', routes); app.use('/users', users);
从字面上其实很好理解,第一是告诉node视图在哪里找,第二是说哪儿会有静态文件,第三就是路由从哪里分析啦。
对照着目录表,这个新新形象还是蛮清爽的嘛!! -
学着配置个简单的路由,就是HelloWorld啦
app.js 中指出,跟路由 '/' 是由routes指定的,那么我们来看看routes是什么鬼,查看下routes下,会有个index.js和users.js,怎么会有两个文件?好吧,我猜是index.js来控制的。不理对不对,先看下index.js再说。var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); }); module.exports = router;
哈,貌似猜对了。文件中指出了'/' 对应的函数。
那我们也来个Hello World?
在.get 函数后面自己加一个:... ... router.get('/helloworld', function(req, res, next) { res.send('Hello World'); }); ... ...
好,然后我们启动服务器,试一下
http://127.0.0.1:3000/helloworld
,是不是就看到了清爽的 Hello World呢?😊😊再来一个,加个变量到路径里面:
/** * :name 作为路径的变量,可以通过程序获得。 */ router.get('/hello/:name', function(req, res, next) { res.send('<h1>Welcome!</h1><br />Hello ' + req.params.name); });
在浏览器中输入
http://127.0.0.1:3000/hello/Arthur
看看是不是内容根据路径上的变量变了呢😊在上面的小栗子中,路由的控制函数的参数里头,都有三个参数,前两个req 和 res 先不说,可是后面那个next是个什么鬼?
实际上express支持一个同一路径绑定多个控制器,然后express默认执行检测到的第一个。如果想让express执行完第一个后,再执行第二个,这时候next就起到作用啦。如下面的例子:/** * :name 作为路径的变量,可以通过程序获得。 */ router.get('/hello/:name', function(req, res, next) { console.log('Say hello to '+ req.params.name); next(); // 执行下一个同名的路由。 }); router.get('/hello/:name', function(req, res, next) { res.send('<h1>Welcome!</h1><br />Hello ' + req.params.name); });
启动这个服务,你会发现,执行完第一个,程序在终端中打印了信息之后,又在浏览器中显示了信息,两个路由同时被执行了。
-
模版引擎
在MVC架构中,模版引擎包含在服务器端。控制器得到用户请求后,从模型获取数据,调用模版引擎。模版引擎以数据和页面模版为输入,生成HTML页面,然后返回给控制器,由控制器交回客户端。
在app.js中,我们已经通过下面两个命令指定了模版的位置以及使用的模版引擎:app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs');
在
routers/index.js
中,我们通过res.render('index', { title: 'Express' });
指定要渲染的模版文件以及要传进模版的数据,那么一个简单的页面就这么建立了。 -
ejs 标签系统
ejs的标签系统非常简单,总共就以下三种标签:- <% code %> JavaScript代码
- <%=code %> 显示替换过 HTML 特殊字符的内容
- <%- code %> 显示原始 HTML 内容
页面布局
Express会自动套用views目录下的layout.ejs布局。这里《node.js开发指南》又开始落后了。按书中的意思,Express创建出来的ejs模版会有一个layout.ejs文件,index.ejs文件只是一个模版片段。实际用Express4.13.4创建出来的项目里,默认layout.ejs和index.ejs是合并在一起的。但并不妨碍我们把它拆成两个。复杂一个index.ejs,改名为layout.ejs,修改代码如下:<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <%- body %> </body> </html>
在修改原来的index.ejs:
<h1><%= title %></h1> <p>Welcome to <%= title %></p> <span style="color:red" >This is my test span</span>
运行服务并在浏览器中打开
http://127.0.0.1:3000
你会发现效果跟原来的一毛一样。片段视图
实际上新的ejs已经取消了partial这个这个视图助手,只能自己迭代然后使用include关键字。
新建一个list.ejs:<!-- list.ejs --> <ul> <% items.forEach(function(listitem) { %> <% include listitem %> <% }) %> </ul>
再为list.ejs建立一个片段视图,补充
<li>
元素:<!-- listitem.ejs --> <li> <%= listitem %> </li>
模版建好了,那么需要指定一个控制器作为页面的入口。在
routers/index.js
中添加代码:// routers/index.js // ... ... /* * 演示片段视图 */ router.get('/list', function(req, res) { res.render('list', { title: 'List', items : [1991, 'arthur', 'express', 'Node.js'] }); }); //... ...
在浏览器中打开
http://127.0.0.1:3000/list
就能看到书中的效果啦。