gpt4 book ai didi

ajax - 如何使用 Express/Jade 在 AJAX 中正确渲染局部 View 和加载 JavaScript 文件?

转载 作者:行者123 更新时间:2023-12-03 07:35:27 25 4
gpt4 key购买 nike

摘要

我正在为我的 Web 应用程序使用 Express + Jade,并且我正在努力为我的 AJAX 导航呈现部分 View 。

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

TL;DR:2 个问题

  • 什么是最干净 最快 使用 Express + Jade 为 AJAX 导航呈现 View 片段的方法?
  • 应该如何加载与每个 View 相关的 JavaScript 文件?

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


  • 问题#1:我试过的

    解决方案 1:为 AJAX 和非 AJAX 请求使用不同的文件

    我的 layout.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")

    我的 page_full.jade 是 :
    extends layout.jade

    block content
    h1 Hey Welcome !

    我的 page_ajax 是 :
    h1 Hey Welcome

    最后在 router.js (表达) :
    app.get("/page",function(req,res,next){
    if (req.xhr) res.render("page_ajax.jade");
    else res.render("page_full.jade");
    });

    缺点 :
  • 正如您可能猜到的,每次我都必须编辑我的 View 两次
    需要改变一些东西。很令人沮丧。


  • 解决方案 2:与 `include` 相同的技术

    我的 layout.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")

    我的 page_full.jade 就是现在 :
    extends layout.jade

    block content
    include page.jade

    我的 page.jade 包含没有任何 layout/block/extend/include 的实际内容:
    h1 Hey Welcome

    我现在在 router.js (表达) :
    app.get("/page",function(req,res,next){
    if (req.xhr) res.render("page.jade");
    else res.render("page_full.jade");
    });

    优势 :
  • 现在我的内容只定义了一次,这样更好。

  • 缺点 :
  • 我仍然需要一个页面的两个文件。
  • 我必须在 上的 Express 中使用相同的技术每路线。一世
    刚刚将我的代码重复问题从 Jade 转移到 Express。折断。


  • 解决方案 3:与解决方案 2 相同,但修复了代码重复问题。

    使用 Alex Ford's technique ,我可以定义我自己的 render函数在 middleware.js :
    app.use(function (req, res, next) {  
    res.renderView = function (viewName, opts) {
    res.render(viewName + req.xhr ? null : '_full', opts);
    next();
    };
    });

    然后改 router.js ( express )至:
    app.get("/page",function(req,res,next){
    res.renderView("/page");
    });

    保持其他文件不变。

    优势
  • 解决了代码重复问题

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


  • 解决方案 4:将逻辑移至 Jade

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

    首先,我需要将一个变量传递给 Jade,它会告诉它它是什么类型的请求:

    middleware.js (表达)
    app.use(function (req, res, next) {  
    res.locals.xhr = req.xhr;
    });

    所以现在我的 layout.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")

    还有我的 page.jade 将是 :
    if (!locals.xhr)
    extends layout.jade

    block content
    h1 Hey Welcome !

    很棒吧?除了这行不通,因为条件扩展在 Jade 中是不可能的。所以我可以从 移动测试page.jade layout.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
    // Shared JS files go here
    script(src="js/jquery.min.js")
    else
    block content

    page.jade 会回到:
    extends layout.jade

    block content
    h1 Hey Welcome !

    优势 :
  • 现在,我每页只有一个文件
  • 我不必重复 req.xhr在每条路线或每条线路上进行测试
    查看

  • 缺点 :
  • 我的模板中有逻辑。不好


  • 概括

    这些都是我想到和尝试过的技巧,但没有一个真正让我信服。难道我做错了什么 ?有更清洁的技术吗?或者我应该使用另一个模板引擎/框架?

    问题#2

    如果 View 有自己的 JavaScript 文件,会发生什么(使用这些解决方案中的任何一个)?

    例如,使用解决方案#4,如果我有两页, page_a.jade page_b.jade 两者都有自己的客户端 JavaScript 文件 js/page_a.js js/page_b.js ,当页面在 AJAX 中加载时会发生什么?

    首先,我需要定义一个 extraJS阻止 layout.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
    // 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

    然后 page_a.jade 将是 :
    extends layout.jade

    block content
    h1 Hey Welcome !
    block extraJS
    script(src="js/page_a.js")

    如果我输入 localhost/page_a在我的 URL 栏中(非 AJAX 请求),我会得到一个编译版本:
    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")

    这看起来不错。但是如果我现在去 page_b会发生什么?使用我的 AJAX 导航?我的页面将是以下内容的编译版本:
    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.js js/page_b.js 都加载在同一页面上。如果存在冲突(相同的变量名等...)会发生什么?
    另外,如果我回到 本地主机/page_a 使用 AJAX,我会有这个:
    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文件应该在我的 block content里这样当我转到另一个页面时它们会被删除。因此,我的 layout.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_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 实际上是在 jQuery 之前加载的,所以它不会工作,因为 jQuery 还没有定义......
    所以我不知道 如何解决这个问题 .我想过在客户端处理脚本请求,使用(例如) jQuery.getScript() ,但客户端必须知道脚本的文件名,看看它们是否已经加载,也许删除它们。我认为不应该在客户端完成。

    我应该如何处理通过 AJAX 加载的 JavaScript 文件?服务器端使用不同的策略/模板引擎?客户端 ?

    如果你做到了这一步,你就是一个真正的英雄,我很感激,但如果你能给我一些建议,我会更感激:)

    最佳答案

    很好的问题。我没有完美的选择,但我会提供我喜欢的解决方案 #3 的变体。与解决方案 3 的想法相同,但将 _full 文件的 jade 模板移动到您的代码中,因为它是样板文件,javascript 可以在整个页面需要时生成它。免责声明:未经测试,但我谦虚地建议:

    app.use(function (req, res, next) {
    var template = "extends layout.jade\n\nblock content\n include ";
    res.renderView = function (viewName, opts) {
    if (req.xhr) {
    var renderResult = jade.compile(template + viewName + ".jade\n", opts);
    res.send(renderResult);
    } else {
    res.render(viewName, opts);
    }
    next();
    };
    });

    随着您的场景变得更加复杂,您可以更聪明地使用这个想法,例如,将此模板保存到带有文件名占位符的文件中。

    当然,这仍然不是一个完美的解决方案。您正在实现真正应该由您的模板引擎处理的功能,这与您最初反对解决方案#3 相同。如果您最终为此编写了超过几十行的代码,那么请尝试找到一种方法将功能放入 Jade 并向他们发送拉取请求。例如,如果 jade “extends” 关键字采用一个参数,该参数可能会禁用扩展 xhr 请求的布局......

    对于您的第二个问题,我不确定任何模板引擎都可以帮助您。如果您使用 ajax 导航,当导航通过一些后端模板魔术发生时,您不能很好地“卸载”page_a.js。我认为您必须为此(客户端)使用传统的 javascript 隔离技术。对于您的具体问题:首先在闭包中实现页面特定的逻辑(和变量),并在必要时在它们之间进行合理的合作。其次,您不必太担心 Hook 双重事件处理程序。假设主要内容在 ajax 导航上被清除,并且那些是附加了事件处理程序的元素,当新的 ajax 内容加载到 DOM 时,这些元素将调用 get reset(当然)。

    关于ajax - 如何使用 Express/Jade 在 AJAX 中正确渲染局部 View 和加载 JavaScript 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25134232/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com