我正在尝试使用Express JS和Handlebars创建一个基本网站。我有两个文件,page1Router.js和page1Router.handlebars。在Handlebars文件中我有:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page 1</title>
</head>
<script id="page1_template" type="text/x-handlebars-template">
<body>
{{#data.info}}
<h1>{{reportMessage 1}}</h1> <br>
{{/data.info}}
<a href="http://localhost:3030/anotherpage">Click here to go to another page.</a>
</body>
</script>
</html>
在JS文件中我有:
var config = require("../config/config").config,
express = require("express"),
router = express.Router(),
logger = require("../logger/logger").logger,
jsdom = require("jsdom"),
$ = require('jquery')(jsdom.jsdom().createWindow()),
Handlebars = require('handlebars'),
source = $("#page1_template").html(),
template = Handlebars.compile(source);
router.get('/page1', homepage);
var data = {
info: [
{message:"Hey this is a message"},
{message:"This is a different message"},
{message:"This is a final message"}
]
};
Handlebars.registerHelper('reportMessage', function(mes) {
if (mes == 1) {
return info[0].message;
} else if (mes == 2) {
return info[1].message;
}
return "This is an error message";
});
function homepage(req, res) {
res.render(__dirname + "/page1Router.handlebars", data);
logger.info(config.Message1);
}
$('body').append(template(data));
module.exports = router;
当我尝试使用&#34; node app&#34;运行服务器时我收到以下错误:
/Users/iantait/BroboticsForever/practice/node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:436
throw new Exception("You must pass a string or Handlebars AST to Handlebar
^
Error: You must pass a string or Handlebars AST to Handlebars.compile. You passed undefined
at new Error (<anonymous>)
at Error.Exception (/Users/iantait/BroboticsForever/practice/node_modules/handlebars/dist/cjs/handlebars/exception.js:13:41)
at compile (/Users/iantait/BroboticsForever/practice/node_modules/handlebars/dist/cjs/handlebars/compiler/compiler.js:436:11)
at HandlebarsEnvironment.hb.compile (/Users/iantait/BroboticsForever/practice/node_modules/handlebars/dist/cjs/handlebars.js:19:12)
at Object.<anonymous> (/Users/iantait/BroboticsForever/practice/routers/page1Router.js:9:27)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
我的问题是:jquery如何知道在哪里寻找&#34; page1_template&#34;?我相信这个错误正在发生,因为jquery没有正确找到&#34; page1_template&#34;脚本,但我不明白为什么。有什么建议??
答案 0 :(得分:7)
看起来您正在混淆服务器端和客户端逻辑,这会导致一些问题。
最大的问题是你打电话给这一行:
source = $("#page1_template").html()
在您实际呈现页面之前 - 事实上,您在Web应用程序启动时调用它 - 而不是在页面呈现之后。当时程序无法访问元素#page1_template
,因此source
可能为null或未定义。
所以回答你的问题,&#34; jquery如何知道在哪里寻找&#34; page1_template&#34;?&#34;,它不知道,并且不能访问它。
另一个合乎逻辑的问题是,您正在调用$('body').append(template(data));
请求处理程序之外的homepage
,但这些处理程序无法正常工作。为了有机会工作,你必须至少把它放在请求处理程序中。
我不太了解jsdom,但据我所知,我不认为这是你正在寻找的解决方案。在服务器端代码中不需要使用它或jQuery。您的服务器逻辑应该能够呈现完整的页面而无需使用jQuery。
你有几个选项,都可以从服务器中杀死jsdom和jQuery。
在服务器上呈现完整页面,并在res.render
请求处理程序(首选)中使用homepage
返回结果。
只需发送文件的静态部分,发出AJAX请求并使用客户端Handlebars脚本来更新您的页面。
切换到快递&#39;首选的模板语言,Jade,除了没有额外的开销外,就像#1一样。
还有更多,但我不会列举它们。
由于您似乎喜欢使用Handlebars,我会回答#1。同样,问题的关键在于Handlebars.compile(source)
行失败了,因为source
不是字符串,因为你试图使用jQuery从你的jsdom实例中获取模板(在您的页面呈现之前很久。请记住,我们编写的这个JS代码存在于服务器上,而不是浏览器中!)。
第1步:获得正确的套餐
摆脱jsdom,jQuery和Handlebars,然后下载'express3-handlebars'(它也适用于express 4)。
第2步:配置快递
以下是您的快递应用应该是什么样子的简单外观。请特别注意我如何配置视图引擎,以便它知道如何处理.handlebars文件。
// Get the dependencies we need
var express = require('express'),
expressHbs = require('express3-handlebars');
// Create a new express app
var app = express();
// Tell express where our base directory is (for static files)
// usually, we do __dirname + '/public', so we have a public folder for public content
app.use(express.static(__dirname));
// Configure a view engine for express, so it knows how to render .handlebars files
// I set the default layout to be main.handlebars
app.engine('handlebars', expressHbs({ defaultLayout: 'main', extname: '.handlebars' }));
app.set('view engine', 'handlebars');
// Set up your route
app.get('/page1', homepage);
// Set up a request handler
function homepage(req, res) {
res.render('page1'); // We'll come back to this in a minute.
}
// Start listening
app.listen(8080);
第3步:在正确的位置获取正确的文件
express3-handlebars在某些位置查找视图文件。它假设您有一个views/
目录,其中有一个views/layouts
文件夹用于布局。
由于我们将express配置为使用main.handlebars
作为我们的模板,因此这是我们的&#34;主布局。&#34;它将用于每个页面,布局引擎将替换{{{body}}}
与您的页面特定信息。
<强>视图/布局/ main.handlebars 强>:
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{title}}</title>
</head>
<body>
{{{body}}}
</body>
</html>
同样,express3-handlebars开始在views
文件夹中查找视图。您在页面中想要的任何内容都会显示在此处,并会插入{{{body}}}
。为简单起见,我没有使用你的Handlebars助手,但你当然可以这样做(阅读文档了解更多信息)。但是,您确实应该尝试在服务器代码中保留逻辑,而不是模板。
<强>视图/ page1.handlebars 强>:
<h1>{{message}}</h1>
<a href="http://localhost:3030/anotherpage">Click here to go to another page.</a>
第4步:将所有内容捆绑在一起
最后,我们只需将一些数据发送到您的视图,以便正确呈现。让我们从上面更新homepage
请求处理程序:
// Set up a request handler
function homepage(req, res) {
// Ideally, here is where you would determine what message to send down
var context = {
title: 'Page 1',
message: 'This is a message'
};
// Render the view in views/page1.handlebars with this data
res.render('page1', context);
}
那应该是全部!现在,我们在将其发送到客户端之前呈现完整的HTML页面,而无需使用Handlebars模板的jQuery或JIT编译。
以下是一些相关文档: