本文共 5439 字,大约阅读时间需要 18 分钟。
平时做项目中的Web应用都是用Asp.Net或者Java,但有时候需要快速做一些小Web的时候,感觉用Asp.Net或者Java都有点重。一开始想学学PHP,但实在不喜欢PHP的语法,所只用PHP写了两个简单的Demo之后就写不下去了。了解到最近Node.js有点热,前景也不错,而且JavaScript平时也都在用,所以决定学习下Node.js。
准备入门,习惯做两件事,一件是在Google上搜索相关的入门教程,参考等;二是去官方网站找找Guide或者Manual。最后花了一两天浏览了些资料,这两个够了:
当然还有其它一些资料,比如博客、论坛之类。不过官方网站上只找到API文档,适合参考不适合入门。所有这些资料主要是浏览一遍,认识下Node.js,然后还是要在实践中学习。
官方下载,安装都很顺利。不过虽然安装时修改了PATH,但是安装好之后命令行不能直接运行“node”,想起Windows有个老毛病——经常安装程序修改了PATH之后不会生效,所以自己又去系统环境变量设置里重新配置了一下PATH,node命令就可用了。
“Helloworld”还是很简单的,把各种教程上的示例都试了下,然后准备写个小Web。Web Helloworld也很简单,不过要想写功能完整的Web,还是得花些精神,所以还是找框架吧。Google出来Express评价不错,也比较主流,所以决定用Express。仍然是Google+官方文档,这两个资料都不错:
简单实践之后准备构思自己的第一个Node.js Web应用。因为懒得写HTML,最近又正好经常写Markdown的文档,所以准备用Markdown来建个站。Markdown解析当然想自己写,所以仍然是老办法,Google。Node.js的Markdown包找到两个,都是Github上:
也不知道哪个好,所以随便选一个,就选了第一个。当然在建站之前还是需要实验下的,基本满足要求,能支持标准的Markdown语法,但有一些小BUG。因为这次目的是熟悉Node.js和Express,所以不纠结这个问题了,以后有空再找更好的Markdown解析包,实在找不到自己写个也不是很麻烦的事情。
一切准备就绪,开始建站,这里记录下建站的详细过程,一步步说明,入门级的。老实说我比较懒,不想自己去准备Express的结构,所以用了传说中最好的Node.js IDE - JetBrain WebStrom。WebStorm新建项目时有“Node.js Express App”模板
然后在Node.js Express App的选项中,选择使用EJS模板引擎和LESS样式引擎。虽然很多人推荐Jade模板引擎,但是这是个新语法,而且也是我不喜欢的那种。还是EJS更贴近ASP和JSP的语法,所以选择它了。至于LESS,写起来肯定要比直接写CSS轻松得多,这个早就有经验了。
Express应用信息和依赖包在package.json中配置。先得把markdown加进来,所以修改WebStorm生成的package.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "name" : "application-name" , "version" : "0.0.1" , "private" : true , "scripts" : { "start" : "node app.js" }, "dependencies" : { "express" : "3.5.0" , "ejs" : "*" , "less-middleware" : "*" , "markdown" : "*" } } |
最后那句 "markdown": "*" 就是新加的内容。package.json是JSON格式,需要使用双引号把属性名和字符串值包起来。虽然Node.js规范推荐大家在编程时使用单引号表示字符串,但这里,单引号是不行的。
Express App的入口是app.js,这个也在package.json中配置:"start"
:
"node app.js"
。WebStorm生成的app.js中是通过3000端口监听服务,因为我的机器上没有安装Web服务器,80端口空着,所以我把端口号改成了80。然后,看app.js的源码,在启动HTTP服务之前配置了两行URL Route。考虑到以后的应用中URL路由配置可能会很长,再加上我有点洁癖,所以我决定尝试把URL路由放在一个独立的脚本中配置,于是在根目录下创建了一个app-routes.js,专们用来配置路由:
1 2 3 4 5 6 | var routes = require( './routes' ); var user = require( './routes/user' ); exports.route = function (app) { app.get( '/' , routes.index); app.get( '/users' , user.list); }; |
然后在app.js中引入app-routes,并调用导出的route方法,顺便把上面没用的require都删了:
1 2 3 | // app.get('/', routes.index); // app.get('/users', user.list); require( './app-routes' ).route(app); |
运行了下,效果不错,路由没问题。剩下的就是解析Markdown的问题了。Markdown文件我准备专门建个目录来保存,所有文件都用其它编辑器(比如Sublime Text)写好放在里面,然后通过在url中直接输入“/文件名”的方式来打开解析后的HTML页面。
然后在routes目录下添加了一个markdown.js,这个脚本根据URL参数,在md目录下选择对应的文件,解析后,通过views目录下新添加的md.ejs模板显示成HTML,所以目录结构就像这个
接着添加路由,将访问请求交给markdown.js来处理
1 2 3 4 5 | var routes = require( './routes' ); var markdown = require( './routes/markdown' ); exports.route = function (app) { app.get( '/(:md)?' , markdown.show); }; |
还有md.ejs模板,需要在<body>标准中显示由Markdown文件转换而来的HTML,所以使用<%- %>标记。
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> < html > < head > < meta http-equiv = "content-type" content = "text/html; charset=utf-8" /> < title ><%= title %></ title > < link rel = 'stylesheet' href = '/stylesheets/style.css' /> </ head > < body > <%- content %> </ body > </ html > |
markdown.js中的处理过程是获取路由参数,再根据参数在md目录下去找对应的文件,如果没找到直接返回404错误。如果找到了就将这个文件的内容读出来,解析成HTML,传递给md.ejs输出到浏览器。同时考虑如果URL不带参数,则说明是访问首页,markdown.js应该直接去解析md/index.md。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var fs = require( "fs" ); var path = require( "path" ); var markdown = require( "markdown" ).markdown; exports.show = function (req, res) { // 获取参数并将参数转换成 var mdName = req.params.md || "index" ; if (!mdName.match(/\.md$/i)) { mdName += ".md" ; } // 根据当前目录和相对目录找到参数对应的md文件 var filename = path.resolve(path.join(__dirname, "../md" , mdName)); // render函数定义符合readFile和callback标准 // 如果md文件读取错误或者没有内容,向浏览器返回404 // 有内容则调用md.ejs渲染HTML页面 var render = function (err, md) { if (err || !md) { res.status(404).send( "Error" ); return ; } var html = markdown.toHTML(md); res.render( "md" , { title: "Markdown Content" , content: html }); }; // 从md文件读取内容,并将读到的内容交能render函数处理 fs.readFile(filename, { encoding: "utf8" }, render); }; |
完工,使用node app.js启动服务,再在浏览器中访问,一切正常,只是——页面太丑了,因为没加样式。修改public/stylesheets/style.less,加入样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | body { margin : 24px ; font : 14px "微软雅黑" , "Lucida Grande" , Helvetica , Arial , sans-serif ; } .h { font-weight : normal ; } h 1 { .h(); font-size : 32px ; } h 2 { .h(); font-size : 24px ; } h 3 { .h(); font-size : 18px ; } .quote { background-color : #e8e8e8 ; border-left : 5px solid #cacaca ; padding : 3px 0 3px 24px ; border-radius: 3px ; margin : 0 ; p { margin : 1px 0 ; } } code { .quote(); font-family : Consolas, Monaco, "Lucida Console" , monospace ; padding : 0 5px ; margin-left : 2px ; margin-right : 2px ; border : 1px solid #cacaca ; } pre { .quote(); border-left-width : 32px ; padding-left : 12px ; code { border : 0 ; padding : 0 ; margin : 0 ; } } blockquote { .quote(); code { background-color : #f8f8f8 ; } } a { color : #666 ; text-decoration : underline ; &:visited { color : #999 ; } &:hover { color : #000 ; } } ul, ol { margin : 0 ; padding : 0 ; li { margin-left : 1.2em ; padding : 0 ; } } ul li { list-style-type : square ; } hr { height : 1px ; border : 0 ; background-color : #999 ; } |
这回才是真正的完工了,看看效果:
本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/1377256,如需转载请自行联系原作者