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

6

我将使用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;

当我尝试运行“node app”服务器时,出现以下错误:
/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 如何知道在哪里查找 "page1_template"?我相信这个错误是因为 jQuery 没有正确地找到 "page1_template" 脚本所致,但我不知道原因。有什么建议吗?
1个回答

9
看起来你混淆了服务器端和客户端逻辑,这导致了一些问题。最大的问题是你在渲染页面之前调用了这行代码:source = $("#page1_template").html(),实际上,在你的网络应用程序启动时调用它,而不是在页面被渲染之后。此时你的程序中没有可访问的元素#page1_template,所以source可能是null或undefined。
因此回答你的问题,“jquery如何知道在哪里查找“page1_template”?”,它不知道,也无法访问它。
另一个逻辑问题是你在homepage请求处理程序之外调用$('body').append(template(data));,这样是行不通的。为了使其有任何机会工作,您至少必须将其放在请求处理程序内部。
我不太了解jsdom,但根据我所知,我认为它不是你正在寻找的解决方案。你的服务器端代码不需要使用它或jQuery。你的服务器逻辑应该能够呈现完整的页面,而无需使用jQuery。
你有几个选择,都可以从服务器上删除jsdom和jQuery。
  1. 在服务器上呈现完整页面,并在homepage请求处理程序中使用res.render返回结果(首选)。

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

  3. 切换到express的首选模板语言Jade,就像#1一样,但没有额外的开销。

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


既然你似乎喜欢使用Handlebars,我会回答问题#1。你的问题核心是 Handlebars.compile(source) 行失败了,因为 source 不是一个字符串,是因为你试图使用 jQuery 从你的 jsdom 实例中获取模板(这个实例在页面渲染之前就被创建了。请记住,我们编写的这段 JS 代码运行在服务器上,而不是浏览器中!)。

第一步:获取正确的包

摆脱 jsdom、jQuery 和 Handlebars,下载 'express3-handlebars'(它也适用于 express 4)。

第二步:配置 express

以下是 express 应用程序的最简结构。请特别注意如何配置视图引擎,以便它知道如何处理 .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);

第三步: 将正确的文件放在正确的位置

express3-handlebars会在特定的位置查找视图文件。它假设您有一个名为views/的目录,并带有一个views/layouts文件夹用于布局。

由于我们配置了express使用main.handlebars作为我们的模板,这是我们的“主要布局”。它将用于每个页面,并且布局引擎将用页面特定的信息替换{{{body}}}

views/layouts/main.handlebars:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        {{{body}}}
    </body>
</html>

再次强调,express3-handlebars会在views文件夹中查找视图。您想要放入页面的任何内容都在此处,并将插入到{{{body}}}中。为简单起见,我没有使用您的Handlebars helper,但您肯定可以这样做(阅读文档以获取更多信息)。但是,您真的应该尽量将逻辑保留在服务器代码中,而不是模板中。

views/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页面发送给客户端之前进行渲染,而不需要使用jQuery或Handlebars模板的JIT编译。

以下是一些相关文档:


这非常有帮助,感谢您抽出时间给我提供如此详细的答案! - Ian Tait

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接