Wal*_*ers 38 ajax layout templating express pug
摘要
我正在使用Express + Jade作为我的Web应用程序,我正在努力为我的AJAX导航渲染部分视图.
我有两个不同的问题,但它们是完全相关的,所以我将它们包括在同一篇文章中.我想这将是一个很长的帖子,但我保证如果你已经在努力解决同样的问题,这很有意思.如果有人花时间阅读并提出解决方案,我会非常感激.
TL; DR:2个问题
要求
我的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")
Run Code Online (Sandbox Code Playgroud)
我的page_full.jade是:
extends layout.jade
block content
h1 Hey Welcome !
Run Code Online (Sandbox Code Playgroud)
我的page_ajax是:
h1 Hey Welcome
Run Code Online (Sandbox Code Playgroud)
最后在router.js(Express)中:
app.get("/page",function(req,res,next){
if (req.xhr) res.render("page_ajax.jade");
else res.render("page_full.jade");
});
Run Code Online (Sandbox Code Playgroud)
缺点:
我的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")
Run Code Online (Sandbox Code Playgroud)
我的page_full.jade现在是:
extends layout.jade
block content
include page.jade
Run Code Online (Sandbox Code Playgroud)
我的page.jade包含没有任何layout/block/extend/include的实际内容:
h1 Hey Welcome
Run Code Online (Sandbox Code Playgroud)
我现在在router.js(Express):
app.get("/page",function(req,res,next){
if (req.xhr) res.render("page.jade");
else res.render("page_full.jade");
});
Run Code Online (Sandbox Code Playgroud)
优点:
缺点:
使用Alex Ford的技术,我可以render在middleware.js中定义自己的函数:
app.use(function (req, res, next) {
res.renderView = function (viewName, opts) {
res.render(viewName + req.xhr ? null : '_full', opts);
next();
};
});
Run Code Online (Sandbox Code Playgroud)
然后将router.js(Express)更改为:
app.get("/page",function(req,res,next){
res.renderView("/page");
});
Run Code Online (Sandbox Code Playgroud)
保持其他文件不变.
好处
缺点
renderView方法感觉很脏.毕竟,我希望我的模板引擎/框架能够为我处理这个问题.我不喜欢在一个页面上使用两个文件,那么如果我让Jade决定要渲染什么而不是Express呢?乍一看,对我来说似乎很不舒服,因为我认为模板引擎根本不应该处理任何逻辑.但是试试吧.
首先,我需要将一个变量传递给Jade,它将告诉它它是什么类型的请求:
在middleware.js(Express)
app.use(function (req, res, next) {
res.locals.xhr = req.xhr;
});
Run Code Online (Sandbox Code Playgroud)
所以现在我的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")
Run Code Online (Sandbox Code Playgroud)
而我的page.jade将是:
if (!locals.xhr)
extends layout.jade
block content
h1 Hey Welcome !
Run Code Online (Sandbox Code Playgroud)
好吧?除非这不起作用,因为在玉中有条件的延伸是不可能的.所以我可以将测试从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
Run Code Online (Sandbox Code Playgroud)
和page.jade将返回:
extends layout.jade
block content
h1 Hey Welcome !
Run Code Online (Sandbox Code Playgroud)
优点:
req.xhr在每个路线或每个视图中重复测试缺点:
这些都是我想到和尝试的技术,但没有一个真正让我信服.难道我做错了什么 ?有清洁技术吗?或者我应该使用另一个模板引擎/框架?
如果视图有自己的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
Run Code Online (Sandbox Code Playgroud)
然后page_a.jade将是:
extends layout.jade
block content
h1 Hey Welcome !
block extraJS
script(src="js/page_a.js")
Run Code Online (Sandbox Code Playgroud)
如果我输入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")
Run Code Online (Sandbox Code Playgroud)
看起来很好.但是,如果我现在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")
Run Code Online (Sandbox Code Playgroud)
js/page_a.js和js/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")
Run Code Online (Sandbox Code Playgroud)
相同的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
Run Code Online (Sandbox Code Playgroud)
对 ?呃....如果我去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")
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到,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();
};
});
Run Code Online (Sandbox Code Playgroud)
当您的场景变得更加复杂时,您可以更加巧妙地运用这个想法,例如将此模板保存到带有文件名占位符的文件中。
当然这仍然不是一个完美的解决方案。您正在实现的功能实际上应该由您的模板引擎处理,与您最初反对解决方案#3 相同。如果您最终为此编写了几十行代码,那么请尝试找到一种方法将该功能适合 Jade 并向他们发送拉取请求。例如,如果 jade“extends”关键字采用一个参数,可以禁用扩展 xhr 请求的布局......
对于你的第二个问题,我不确定任何模板引擎可以帮助你。如果您使用 ajax 导航,则当导航通过某些后端模板魔术发生时,您无法很好地“卸载”page_a.js。我认为你必须为此使用传统的 javascript 隔离技术(客户端)。对于您的具体问题:首先,在闭包中实现页面特定的逻辑(和变量),并在必要时在它们之间进行合理的合作。其次,您不必太担心连接双事件处理程序。假设在 ajax 导航上清除了主要内容,并且这些元素附加了事件处理程序,当新的 ajax 内容加载到 DOM 中时,它们将调用 get Reset(当然)。
| 归档时间: |
|
| 查看次数: |
15030 次 |
| 最近记录: |