如何使用Express/Jade在AJAX中正确呈现局部视图并加载JavaScript文件?

如何使用Express/Jade在AJAX中正确呈现局部视图并加载JavaScript文件?,ajax,layout,express,pug,templating,Ajax,Layout,Express,Pug,Templating,摘要 我正在为我的web应用程序使用Express+Jade,我正在努力为AJAX导航渲染部分视图 我有两个不同的问题,但它们是完全相连的,所以我把它们放在同一篇文章里。 我想这将是一篇很长的文章,但我保证如果你已经为同样的问题挣扎过的话,这会很有趣。如果有人花时间阅读并提出解决方案,我将不胜感激 TL;博士:2个问题 对于使用Express+Jade的AJAX导航,渲染视图片段的最干净的和最快的方法是什么 如何加载与每个视图相关的JavaScript文件 要求 我的Web应用需要与已禁用

摘要

我正在为我的web应用程序使用Express+Jade,我正在努力为AJAX导航渲染部分视图

我有两个不同的问题,但它们是完全相连的,所以我把它们放在同一篇文章里。 我想这将是一篇很长的文章,但我保证如果你已经为同样的问题挣扎过的话,这会很有趣。如果有人花时间阅读并提出解决方案,我将不胜感激

TL;博士:2个问题

  • 对于使用Express+Jade的AJAX导航,渲染视图片段的最干净的最快的方法是什么
  • 如何加载与每个视图相关的JavaScript文件
要求

  • 我的Web应用需要与已禁用的用户兼容
    JavaScript
  • 如果启用了JavaScript,则只有页面本身的内容(而不是 整个布局)应该从服务器发送到客户端
  • 该应用程序需要速度快,并加载尽可能少的字节

问题1:我尝试了什么 解决方案1:为AJAX和非AJAX请求提供不同的文件 我的布局。jade是:

doctype html
    html(lang="fr")
        head
            // Shared CSS files go here
            link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
        body
            div#main_content
                block content
            // Shared JS files go here
            script(src="js/jquery.min.js")
我的页面已满。jade是:

extends layout.jade

block content
    h1 Hey Welcome !
我的页面是:

h1 Hey Welcome
最后在router.js(Express)中:

缺点

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
  • 正如你可能猜到的,每次我编辑视图时,我都必须编辑两次 我需要改变一下。相当令人沮丧

解决方案2:与“include”相同的技术` 我的布局。jade保持不变:

doctype html
    html(lang="fr")
        head
            // Shared CSS files go here
            link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
        body
            div#main_content
                block content
            // Shared JS files go here
            script(src="js/jquery.min.js")
我的页面已满。jade现在是:

extends layout.jade

block content
   include page.jade
My页面。jade包含实际内容,没有任何布局/块/扩展/包括:

h1 Hey Welcome
我现在在router.js(Express)中看到:

优势

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
  • 现在我的内容只定义一次,这样更好
缺点

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
  • 我一页还需要两个文件
  • 我必须在每条路线上的Express中使用相同的技巧。我 刚把我的代码重复问题从Jade转移到Express。啪

解决方案3:与解决方案2相同,但修复了代码重复问题。 使用,我可以在middleware.js中定义我自己的
渲染
函数:

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
然后将router.js(Express)更改为:

保持其他文件不变

优势

  • 它解决了代码重复问题
缺点

  • 我一页还需要两个文件
  • 定义我自己的
    renderView
    方法感觉有点脏。毕竟,我 希望我的模板引擎/框架能为我处理这个问题

解决方案4:将逻辑转移到Jade 我不喜欢在一个页面上使用两个文件,所以如果我让Jade来决定渲染什么而不是Express呢?乍一看,我觉得很不舒服,因为我认为模板引擎应该而不是处理任何逻辑。但是让我们试试看

首先,我需要向Jade传递一个变量,该变量将告诉它请求的类型:

middleware.js(Express)中

因此,现在我的布局。jade将与以前相同:

doctype html
    html(lang="fr")
        head
            // Shared CSS files go here
            link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
        body
            div#main_content
                block content
            // Shared JS files go here
            script(src="js/jquery.min.js")
而我的页面。jade将是:

if (!locals.xhr)
    extends layout.jade

block content
   h1 Hey Welcome !
extends layout.jade

block content
   h1 Hey Welcome !
block extraJS
   script(src="js/page_a.js")
很好,嗯?但这不起作用,因为在Jade中条件扩展是不可能的。因此,我可以将测试从页面.jade移动到布局。jade

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
页面。jade将返回:

extends layout.jade

block content
   h1 Hey Welcome !
优势

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
  • 现在,我每页只有一个文件
  • 我不必在每条路线或每条路线上重复
    req.xhr
    测试 看法
缺点

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
  • 我的模板中有逻辑。不好

总结 这些都是我想到并尝试过的技巧,但没有一种真正让我信服。我做错什么了吗?是否有更清洁的技术?还是应该使用其他模板引擎/框架?


问题2 如果视图有自己的JavaScript文件,会发生什么情况(使用任何这些解决方案)?

例如,使用解决方案#4,如果我有两个页面,page#a.jadepage#b.jade,它们都有自己的客户端JavaScript文件js/page#a.jsjs/page#b.js,在AJAX中加载这些页面时会发生什么

首先,我需要在布局中定义一个
extraJS
块。jade

app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
        res.render(viewName + req.xhr ? null : '_full', opts);
        next();
    };
 });
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                // Shared JS files go here
                script(src="js/jquery.min.js")
                // Specific JS files go there
                block extraJS
 else
     block content
     // Specific JS files go there
     block extraJS
然后页面a.jade将是:

if (!locals.xhr)
    extends layout.jade

block content
   h1 Hey Welcome !
extends layout.jade

block content
   h1 Hey Welcome !
block extraJS
   script(src="js/page_a.js")
如果我在我的URL栏(非AJAX请求)中键入
localhost/page_a
,我将得到以下内容的编译版本:

doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
            body
               div#main_content
                  h1 Hey Welcome A !
               script(src="js/jquery.min.js")
               script(src="js/page_a.js")
doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                  h1 Hey Welcome B !
                  script(src="js/page_b.js")
               script(src="js/jquery.min.js")
               script(src="js/page_a.js")
看起来不错。但是如果我现在使用AJAX导航进入
page_b
,会发生什么呢?我的页面将是以下内容的编译版本:

doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
            body
               div#main_content
                  h1 Hey Welcome A !
               script(src="js/jquery.min.js")
               script(src="js/page_a.js")
doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                  h1 Hey Welcome B !
                  script(src="js/page_b.js")
               script(src="js/jquery.min.js")
               script(src="js/page_a.js")
js/page_a.jsjs/page_b.js都加载在同一页面上。如果存在冲突(相同的变量名等),会发生什么情况? 另外,如果我使用AJAX返回到localhost/page_a,我会得到以下结果:

doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                  h1 Hey Welcome B !
                  script(src="js/page_a.js")
               script(src="js/jquery.min.js")
               script(src="js/page_a.js")
相同的JavaScript文件(page_a.js)在同一页面上加载了两次!它是否会导致冲突,每次事件都会重复发生? 不管是不是这样,我不认为这是干净的代码

所以你可能会说特定的JS文件应该在我的
块内容中
,这样当我转到另一个页面时,它们就会被删除。因此,我的布局.jade应该是:

if (!locals.xhr)
    doctype html
       html(lang="fr")
           head
               // Shared CSS files go here
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
           body
               div#main_content
                    block content
                    block extraJS
                // Shared JS files go here
                script(src="js/jquery.min.js")
 else
     block content
     // Specific JS files go there
     block extraJS
对吧??错误……如果我转到
localhost/page\u a
,我将得到以下内容的编译版本:

doctype html
       html(lang="fr")
           head
               link(type="text/css",rel="stylesheet",href="css/bootstrap.min.css")
            body
               div#main_content
                  h1 Hey Welcome A !
                  script(src="js/page_a.js")
               script(src="js/jquery.min.js")
正如您可能已经注意到的,js/page_a.js实际上是在b中加载的