Handlebars.js如何使用jQuery和Nodejs Express?

时间:2014-06-10 15:59:25

标签: jquery express handlebars.js

我正在尝试使用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;脚本,但我不明白为什么。有什么建议??

1 个答案:

答案 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。

  1. 在服务器上呈现完整页面,并在res.render请求处理程序(首选)中使用homepage返回结果。

  2. 只需发送文件的静态部分,发出AJAX请求并使用客户端Handlebars脚本来更新您的页面。

  3. 切换到快递&#39;首选的模板语言,Jade,除了没有额外的开销外,就像#1一样。

  4. 还有更多,但我不会列举它们。


  5. 由于您似乎喜欢使用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编译。

    以下是一些相关文档: