Node.js 動手實現(xiàn)簡單的模板引擎(列表渲染)

準備HTML模板文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>電影列表</h1>
    <hr>
    <table width="500" border="1" cellspacing="0" cellpadding="0">
        <thead>
            <tr>
                <th width="200">名稱</th>
                <th width="200">導演</th>
                <th width="500">簡介</th>
            </tr>
        </thead>
        <tbody>
        <!-- 自定義模板語法,列表的渲染 -->
        {%for {movies} %}
            <tr>
                <td>{{item.name}}</td>
                <td>{{item.author}}</td>
                <td>{{item.brief}}</td>
            </tr>
         {%endfor%}
        </tbody>
    </table>
</body>
</html>

創(chuàng)建服務(wù)器server.js 文件

//引入http和文件系統(tǒng)(均為node內(nèi)置模塊,無需安裝)
let http = require('http');
let fs = require('fs');
/**
 * 模擬數(shù)據(jù)庫
 */
const MockDataBase = {
    //定義一個查詢電影記錄的方法搁凸,返回一個movie對象
    getMovie : function(){
        let movie =  {
            name:'黑暗正義聯(lián)盟:天啟星戰(zhàn)爭',
            brief:'正義聯(lián)盟集結(jié)地球上所有超級英雄一起對抗強大的反派達克賽德藕届。',
            author:'馬特·皮特斯 Matt Peters'
          };
          return movie;
    },
    //定義一個查詢電影列表的方法方法,返回一個movie列表
    getMovies : function(){
        let movies =  [{
            name:'斗戰(zhàn)勝佛之大圣之淚',
            brief:'成為斗戰(zhàn)勝佛的孫悟空竟被怨靈蠱惑赠摇,唐三藏遭遇滅頂之災(zāi)!危急關(guān)頭,孫悟空揪出怨靈源頭课竣,卻發(fā)現(xiàn)她竟是與自己有三百年緣分的天人界女神——“幸運星”!為了找出“幸運星”黑化的原因置媳,拯救唐三藏于樟,孫悟空踏上了一場回到過去之旅,卻最終流下了一滴眼淚拇囊。大圣之淚迂曲,為何而流,為誰而流寥袭?',
            author:'鐘智行 Frankie Chung'
          },{
            name:'獵謊者',
            brief:'三個月前路捧,某市發(fā)生了一起惡性綁架殺人案。三個月后传黄,兇手與被害人都死于車禍杰扫。初出茅廬的女警韓燁找到了案件的幸存者林超凡,向他求證案件發(fā)生的經(jīng)過膘掰。但隨著調(diào)查的深入章姓,韓燁發(fā)現(xiàn)林超凡的很多證詞都存在漏洞,再三逼問之下炭序,林超凡無奈坦白了另一個版本的故事啤覆,但案件真相遠沒有這么簡單,幾乎每個人都在說謊惭聂,而故事也開始不斷反轉(zhuǎn)窗声。',
            author:'廉欣 Xin Lian'
          },{
            name:'天啟大爆炸',
            brief:'《天啟大爆炸》以中國古代曾真實發(fā)生的神秘爆炸為原型,加以天馬行空的巧妙構(gòu)思辜纲,為觀眾解封至今困惑世人的隱秘真相笨觅。神秘機構(gòu)“夜行司”追蹤離奇謎團勇闖“無相城”,一場關(guān)乎百姓蒼生命運博弈就此展開耕腾。',
            author:'黃羿 Yi Huang / 曾黎'
          }];
          return movies;
    }
}
/**
 * 實現(xiàn)一個簡單的模板引擎见剩,接收模板路徑和數(shù)據(jù)模型兩個參數(shù)。
 * 原理就是讀取模板文件扫俺,根據(jù)自定義的模板語法解析苍苞,然后替換為模型數(shù)據(jù)
 */
function defaultTemplateEngine(path,model){
    console.log('執(zhí)行模板引擎,渲染數(shù)據(jù)。')
    fs.readFile(path,{encoding:"utf-8",flag:"r"},(err,data)=>{
        if(err){
            this.end(err);
        }else{
            /**
             * 先使用正則匹配循環(huán)的變量和循環(huán)的內(nèi)容
             * 也就是index.html模板中的 
             * 
             * movies 變量
             * 和 以下循環(huán)的內(nèi)容
             * <tr>
             *      <td>{{item.name}}</td>
             *      <td>{{item.author}}</td>
             *      <td>{{item.brief}}</td>
             *  </tr>
             * 
             */
           
            let reg = /\{\%for \{(.*?)\} \%\}(.*?)\{\%endfor\%\}/igs;
            while(result = reg.exec(data)){
                let strKey = result[1].trim();
                //通過key值獲取電影列表
                let strValueArr = model[strKey];
                let listStr = '';
                    /**
                     * 再循環(huán)電影列表羹呵,生成多條以下內(nèi)容骂际,并替換到HTML字符串
                     * <tr>
                     *      <td>{{item.name}}</td>
                     *      <td>{{item.author}}</td>
                     *      <td>{{item.brief}}</td>
                     *  </tr>
                     */
                strValueArr.forEach((item,index)=>{
                    listStr += replaceVar(result[2],{'item':item});
                })
                //替換到HTML字符串
                data = data.replace(result[0],listStr);
        
            }


            /**
             * 返回渲染完成的html內(nèi)容
             * 因為回調(diào)函數(shù)使用的是匿名函數(shù),所在可以使用this對象冈欢,此處的this指向的是調(diào)用者歉铝,
             * 此例中,調(diào)用者是http請求的響應(yīng)對象res凑耻,end是res對象中內(nèi)置的一個函數(shù)太示,此函數(shù)作用是結(jié)束請求,并發(fā)送響應(yīng)數(shù)據(jù)香浩。
             */
            this.end(data);
        }
    })
}


/**
 * 正則匹配每一條電影中的每個屬性
 * <tr>
 *      <td>{{item.name}}</td>
 *      <td>{{item.author}}</td>
 *      <td>{{item.brief}}</td>
 *  </tr>
 */
function replaceVar(data,model){
    let regex = /\{\{(.*?)\}\}/igs
    let result;
    while(result = regex.exec(data)){
        let strKey = result[1].trim();
        //替換
        console.log(strKey)
        let strValue = eval('model.' + strKey);
        data = data.replace(result[0],strValue);
    }
    return data;

}
/**
 * 實現(xiàn)一個簡單的模型引擎過濾器
 * 此過濾器中向res對象追加了模板渲染引擎函數(shù)render类缤。
 */
function templateEngineFilter(req,res){
    if(req.url == '/'){
        console.log('執(zhí)行模板引擎過濾器,向響應(yīng)對象追加一個模板渲染引擎函數(shù)')
        res.render = defaultTemplateEngine;
    }
}    
//創(chuàng)建一個服務(wù)
let server = http.createServer();
//服務(wù)監(jiān)聽請求
server.on('request',async function(req,res){
    console.log('收到請求:' + req.url);
    //執(zhí)行請求過濾器
    templateEngineFilter(req,res);
     //設(shè)置響應(yīng)類型及字符集編碼
    res.setHeader('Content-Type','text/html;charset=utf-8')
    //如果請求路徑是根路徑 ‘/’ 則返回電影信息頁面邻吭,否則返回404
    if(req.url=='/'){
        //從數(shù)據(jù)庫中獲取電影信息
      let movies = await MockDataBase.getMovies();
      //調(diào)用響應(yīng)對象的模板渲染函數(shù)呀非,將數(shù)據(jù)渲染到頁面
      let model = {"movies":movies};
      res.render('./index.html',model)
    }else{
        res.end('404!資源不存在镜盯。')
    }
})
//服務(wù)監(jiān)聽80端口
server.listen(80,function(){
    console.log('服務(wù)啟動成功。')
})

運行命令猖败,啟動服務(wù)

node server.js
server.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末速缆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恩闻,更是在濱河造成了極大的恐慌艺糜,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幢尚,死亡現(xiàn)場離奇詭異破停,居然都是意外死亡,警方通過查閱死者的電腦和手機尉剩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人继低,你說我怎么就攤上這事勉失。” “怎么了皂林?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵朗鸠,是天一觀的道長。 經(jīng)常有香客問我础倍,道長烛占,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任沟启,我火速辦了婚禮忆家,結(jié)果婚禮上犹菇,老公的妹妹穿的比我還像新娘。我一直安慰自己弦赖,他們只是感情好项栏,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蹬竖,像睡著了一般沼沈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上币厕,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天列另,我揣著相機與錄音,去河邊找鬼旦装。 笑死页衙,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的阴绢。 我是一名探鬼主播店乐,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼呻袭!你這毒婦竟也來了眨八?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤左电,失蹤者是張志新(化名)和其女友劉穎廉侧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體篓足,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡段誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了栈拖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片连舍。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涩哟,靈堂內(nèi)的尸體忽然破棺而出烟瞧,到底是詐尸還是另有隱情,我是刑警寧澤染簇,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布参滴,位于F島的核電站,受9級特大地震影響锻弓,放射性物質(zhì)發(fā)生泄漏砾赔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望暴心。 院中可真熱鬧妓盲,春花似錦、人聲如沸专普。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檀夹。三九已至筋粗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娜亿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工蚌堵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留买决,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓吼畏,卻偏偏與公主長得像督赤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泻蚊,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350