您好,登錄后才能下訂單哦!
平時做項目中的Web應用都是用Asp.Net或者Java,但有時候需要快速做一些小Web的時候,感覺用Asp.Net或者Java都有點重。一開始想學學PHP,但實在不喜歡PHP的語法,所只用PHP寫了兩個簡單的Demo之后就寫不下去了。了解到最近Node.js有點熱,前景也不錯,而且JavaScript平時也都在用,所以決定學習下Node.js。
準備入門,習慣做兩件事,一件是在Google上搜索相關的入門教程,參考等;二是去官方網站找找Guide或者Manual。最后花了一兩天瀏覽了些資料,這兩個夠了:
Node.js入門>>一本全面的Node.js教程
Node.js概述(by 阮一峰)
當然還有其它一些資料,比如博客、論壇之類。不過官方網站上只找到API文檔,適合參考不適合入門。所有這些資料主要是瀏覽一遍,認識下Node.js,然后還是要在實踐中學習。
官方下載,安裝都很順利。不過雖然安裝時修改了PATH,但是安裝好之后命令行不能直接運行“node”,想起Windows有個老毛病——經常安裝程序修改了PATH之后不會生效,所以自己又去系統環境變量設置里重新配置了一下PATH,node命令就可用了。
“Helloworld”還是很簡單的,把各種教程上的示例都試了下,然后準備寫個小Web。Web Helloworld也很簡單,不過要想寫功能完整的Web,還是得花些精神,所以還是找框架吧。Google出來Express評價不錯,也比較主流,所以決定用Express。仍然是Google+官方文檔,這兩個資料都不錯:
官方的 Express Guide
中文翻譯的 Express 新手指南
簡單實踐之后準備構思自己的第一個Node.js Web應用。因為懶得寫HTML,最近又正好經常寫Markdown的文檔,所以準備用Markdown來建個站。Markdown解析當然想自己寫,所以仍然是老辦法,Google。Node.js的Markdown包找到兩個,都是Github上:
https://github.com/evilstreak/markdown-js
https://github.com/andris9/node-markdown
也不知道哪個好,所以隨便選一個,就選了第一個。當然在建站之前還是需要實驗下的,基本滿足要求,能支持標準的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:
{ "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,專們用來配置路由:
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都刪了:
// 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來處理
var routes = require('./routes'); var markdown = require('./routes/markdown'); exports.route = function (app) { app.get('/(:md)?', markdown.show); };
還有md.ejs模板,需要在<body>標準中顯示由Markdown文件轉換而來的HTML,所以使用<%- %>標記。
<!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。
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,加入樣式
body { margin: 24px; font: 14px "微軟雅黑", "Lucida Grande", Helvetica, Arial, sans-serif; } .h { font-weight: normal; } h2 { .h(); font-size: 32px; } h3 { .h(); font-size: 24px; } h4 { .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; }
這回才是真正的完工了,看看效果:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。