查看支持ajax和直接调用的引擎

时间:2015-06-05 18:03:43

标签: javascript json node.js express viewengine

我正在寻找一种方法来在Node.js(Express)中提供模板,“正常”呈现为HTML并呈现为JSON,如果是使用ajax请求的话。

假设我在swig中有这样的模板:

{% extends 'layout.html' %}
{% block title %}Default Page{% endblock %}

{% block body %}
  <p>Hi, {{ name }}.</p>
{% endblock %}

现在,如果我使用浏览器发出正常请求,swig将使用layout.html作为布局呈现文件。
但是,如果我使用ajax(或?partial之类的参数)发出请求,我希望将块作为JSON,而不是在layout.html中呈现:

{
  "title": "Default Page",
  "body": "<p>Hi, Dave.</p>"
}

swig的选择是任意的,它可以是任何支持使用块进行布局继承的视图引擎。

我在swig和Nunjucks的文档中搜索了一个基于请求来影响模板渲染的简单方法,但我没有提出一个想法(没有它完全矫枉过正)。

1 个答案:

答案 0 :(得分:3)

简化了我对您具体用例的回答:

您可以通过使用&#34;中间件覆盖&#34;。

轻松完成此操作
app.use(function (req, res, next) {
  var oldRender = res.render.bind(res);
  res.render = function (viewName, viewData) {
    viewData.xhr = req.xhr;
    if (!req.xhr) {
      res.render(viewName, viewData);
    } else {
      res.render(viewName, viewData, function (err, renderedView) {
        if (err) return next(err);
        res.json({
          url: req.url, // In case you want to use the HTML5 history API to update the URL in-place in the client's browser.
          title: viewData.title,
          view: renderedView
        });
      });
    }
  };
});

理想情况下,您的视图引擎应该能够执行以下操作:

{% if !xhr %} 
  {% extends 'layout.html' %}
{% endif %}

现在当你致电res.render('someView', { title: 'some title' });时,它会编译一个完整的视图并将其发送下来,或者如果它是一个XHR请求,那么它将发送一个带有请求URL的JSON blob,页面标题,并将渲染视图作为字符串。然后,您可以在客户端上动态更新页面。

如果您的模板引擎不支持条件extends,那么您可以通过一些&#34; hack&#34;来解决这个问题。原样。您需要两个视图(伪代码):

// someView
<p>Hi, {{ name }}</p>

// someView_full
{% extends 'layout.html' %}
{% block title %}Default Page{% endblock %}

{% block body %}
  {% include 'someView' %}
{% endblock %}

然后修改中间件函数,以便在视图名称不是AJAX请求时将"_full"附加到视图名称。

 if (!req.xhr) {
   res.render(viewName + "_full", viewData);
 } else { ... }

<击>

编辑还有另一种方法可以避免创建第二个小桥视图,甚至可以将每个extends包裹在每个视图的条件中。我发现了这种方法here。事实证明,您可以在布局文件中有条件地创建内容块,从而实现这一目标:

// layout
{% if !xhr %}
  <html>
    <head>
      <title>My Awesome Page</title>
    </head>
    <body>
      {% block body %}{% endblock %}
    </body>
  </html>
{% else %}
  {% block body %}{% endblock %}
{% endif %}

这样,布局文件将决定是否包含周围标记。

PS - req.xhr仅在发出AJAX请求的客户端框架包含x-requested-with header set to "XMLHttpRequest"时提示(提示:大多数情况下)。如果你的框架没有包含那个标题,那么你可以选择切换,或者至少你应该能够设置自定义标题并自己包含它。

您可以使用您在问题中建议的查询字符串变量,但使用此请求标头是向服务器传达请求是AJAX的标准约定,并且通常在客户端框架中默认打开。这就是Express有req.xhr内置的原因:)