在分析轉義Handlebars+express問題之前先把nodejs+handlebars+express的項目構建過程說明。
express 4+handlebars構建項目快捷的方式是:
如圖可選ejs/jade/hbs等模板引擎,現在我們選hbs(注意express的版本是4.0+)
我選擇整合handlebars的方式是在已有的nodejs項目上引入 express-handlebars github地址:github
- 在已有express4 構建的項目上安裝
npm install express-handlebars
- app.js裏添加如下內容(替換以前的引擎模板例如ejs):
var exphbs = require('express-handlebars');
var hbsHelper = require('./util/hbsHelper');
app.set('views', path.join(__dirname, 'views'));
app.engine('.hbs', exphbs({
layoutsDir: 'views',
defaultLayout: 'layout',
extname: '.hbs',
helpers:hbsHelper
}));
app.set('view engine', '.hbs');
這個hbsHelper.js是我自己寫的:
var helper = {section: function(name, block){
if(!this._sections) this._sections = {};
this._sections[name] = block.fn(this);
return null;
}
}
module.exports = helper
3 客戶端頁面views
layout.hbs
<!DOCTYPE html>
<html>
<head>
{{>head}}
{{{_sections.css}}}
</head>
<body>
{{>header}}
{{{body}}}
{{>weather}}
{{>footer}}
{{{_sections.js}}}
</body>
</html>
其中footer(對應目錄文件: views/partials/footer.hbs)引入的是js,如下:
<script src="javascripts/lib/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.min.js"></script>
如此就簡要的說明了nodejs+express+handlebars整合過程。
以下是客戶端數據請求加載過程說明及問題分析:
客戶端頁面數據加載
方式一: 向服務端發出路由請求的時候獲取數據
路由配置:routes/index.js
var express = require('express');
var router= express.Router();
router.get('/base-dd', function(req, res, next) {
res.render('base-dd',{ daduis: [
{
"id": 1,
"name": "<p>一大隊</p>",
"responsiblearea": "陸家嘴,北蔡、六裏、東明部分地區"
},
{
"id": 2,
"name": "二大隊",
"responsiblearea": "迪斯尼,北蔡、六裏、東明部分地區"
},
{
"id": 3,
"name": "三大隊",
"responsiblearea": "張江高科,北蔡、六裏、東明部分地區"
}
] });
});
module.exports = router;
數據顯示頁面:demo.hbs
<!--demo.hbs的內容會被添加到layout.hbs {{{body}}}裏
(是否要用佈局hbs可自己配置)-->
<section class="panel">
<table>
<thead>
<tr>
<th>大隊名稱</th><th>責任區域</th>
</tr>
</thead>
<tbody id="tableList" >
{{#each daduis}}
<td>{{{name}}}</td>
<td>{{responsiblearea}}</td>
</tr>
{{/each}}
</tbody>
</table>
</section>
這種方式就是在客戶端發出/base-dd路由請求後,通過路由配置裏的res.render(‘base-dd’,{daduis:[..]})實現傳參,把數組daduis傳到到 {{#each daduis}},通過handlebars模板引擎遍歷數組,渲染出一行行帶數據的dom(tr)。
方式二:路由配置裏不傳參數,在頁面已經加載完成後,在js($(document).ready(function(){….});)裏主動發出ajax請求獲取數據。
路由配置:routes/index.js
var express = require('express');
var router= express.Router();
router.get('/base-dd', function(req, res, next) {
res.render('base-dd');
});
module.exports = router;
數據顯示頁面:demo.hbs
<section class="panel">
<table>
<thead>
<tr>
<th>大隊名稱</th><th>責任區域</th>
</tr>
</thead>
<tbody id="tableList" >
</tbody>
</table>
</section>
{{#section 'js'}}
<script src="javascripts/demo.js"></script>
<script id="tableList_template" type="text/x-handlebars-template">
\{{#each daduis}}
<tr>
<td>\{{name}}</td>
<td">{{responsiblearea}}</td>
</tr>
\{{/each}}
</script>
{{/section}}
引用的demo.js
$(document).ready(function(){
showDaduiHelper();
});
function showDaduiHelper(){
$.get("/dadui/queryAll", function(result){
var data = {daduis:result};
var source = $("#tableList_template").html();
var template = Handlebars.compile(source);
console.log(data);
$("#tableList")[0].innerHTML = template(data);
testHandlebars();
});
}
這種方式就是通過ajax請求獲得數據daduis, 通過Handlebars.compile
編譯模板$("#tableList_template")
,最後template(data)
把數據注入模板並且把dom innerHTML
填入到$("#tableList")
裏。
問題:
仔細看<script id="tableList_template" type="text/x-handlebars-template"></script>
裏handlebars大括號的使用方式,是不是每個大括號前面都有\
轉義符號? 爲什麼轉義?
加入我們不轉義:
<script id="tableList_template" type="text/x-handlebars-template">
{{#each daduis}}
<tr>
<td>{{name}}</td>
<td">{{responsiblearea}}</td>
</tr>
{{/each}}
</script>
最後渲染出頁面爲空,不顯示錶格!
爲啥呢?
因爲在res.render('base-dd');
後,在showDaduiHelper();
前,handlebars已經將tableList_template
裏的數據進行注入並渲染成dom,由於res.render('base-dd')
未傳參數,daduis自然就是null,也就不會執行{{#each daduis}}
,所以是空的!,如圖:
所以我們就在所有handlebars標籤前面加上轉義符號“\”,這樣第一次加載渲染頁面的時候,服務端視圖引擎就“不認識”這些handlebars標籤,如圖:
從而躲過第一次由服務端render引發的數據注入,再執行$(document).ready(function(){ showDaduiHelper();});
後,客戶端通過ajax主動請求數據,重新編譯模板並加載數據, 渲染出正確的dom。
結合express: http://wiki.jikexueyuan.com/project/express-mongodb-setup-blog/handlebars.html
使用Handlebars模塊化你的頁面:https://www.jianshu.com/p/a38ec7ef339a