尊敬的黑客,
我希望在Jade模板中过滤一个充满Markdown的字符串。 我在变量中有Markdown。
Jade在Markdown中插入变量就好了:
此:
var jade = require('jade');
var jade_string = [
':markdown',
' ## This is markdown!',
' * First',
' * #{var2}',
' * Third'
].join('\n');
var fn = jade.compile( jade_string, { pretty: true } );
console.log( fn( { var1: "First!", var2: "Second!" } ) );
想到这个:
<h2>This is markdown!</h2>
<ul>
<li>First</li>
<li>Second!</li>
<li>Third</li>
</ul>
然而,我所拥有的是变量中的实际完整Markdown。 这个:
var jade = require('jade');
var jade_string = [
'div.markedup',
' :markdown',
' \\#{var2}'
].join('\n');
var fn = jade.compile( jade_string, { pretty: true } );
var markdown = [
'## I am marked!',
'* One',
'* Two'
].join('\n');
console.log( fn( { var1: "First!", var2: markdown } ) );
仅提供此:
<div class="markedup"><p>## I am marked!
* One
* Two</p>
</div>
因此,我认为Jade在执行任何变量之前过滤了块 插值,然后在结果HTML中插入变量。这是 如果您想在Markdown中编写模板,那很好,但并不多 如果您想在Markdown中编写内容,请提供帮助。
我知道我可以通过更多编程解决这个问题,但我觉得我
必须遗漏一些东西。毕竟,持有Markdown内容的片段
数据库并将生成的HTML片段填充到模板中似乎
:markdown
过滤器最明显的用例。
在Jade中有“正常”的方法吗?
非常感谢未来的启蒙。
答案 0 :(得分:4)
我认为答案更多是编程,但我会告诉你我的工作。我使用自定义中间件,让我在进入最终的HTML文档输出之前结合任意变换过程。所以,例如,我在middleware.js模块中有以下过滤器,我将依次解释。
如此简单的视图只需使用普通的玉石及其各种过滤器来降价,javascript,coffeescript。一些观点,例如博客文章,需要更复杂的中间件链,就像这样。
首先,根据请求,我建立了包含此响应的核心内容的文件,并将其设置为res.viewPath
上的属性。这可以是原始HTML片段文件或markdown文件。然后我通过一系列中间件转换发送响应。我使用res.html
和res.dom
来存储响应的中间表示。
这个只存储原始HTML(只是一个没有头部或布局的文档正文片段)。
html = function(req, res, next) {
if (!/\.html$/.test(res.viewPath)) return next();
return fs.readFile(res.viewPath, "utf8", function(error, htmlText) {
res.html = htmlText;
return next(error);
});
};
这个将markdown文件转换为HTML(使用markdown-js模块)。
markdownToHTML = function(req, res, next) {
if (!/\.md$/.test(res.viewPath)) return next();
return fs.readFile(res.viewPath, "utf8", function(error, markdownText) {
res.html = markdown(markdownText);
return next(error);
});
};
我有一个子布局,在我的主布局中,但围绕每个博客文章。所以我在这里的子布局中包装博客文章。 (未显示的单独代码从json元数据文件生成res.post
对象。)
blogArticle = function(req, res, next) {
var footerPath, post;
post = res.post;
footerPath = path.join(__dirname, "..", "templates", "blog_layout.jade");
return fs.readFile(footerPath, "utf8", function(error, jadeText) {
var footerFunc;
if (error) return next(error);
footerFunc = jade.compile(jadeText);
res.html = footerFunc({
post: post,
body: res.html
});
return next();
});
};
现在我将布局包裹在主要内容HTML中。请注意,我可以在此处设置页面标题之类的内容,或者等到稍后,因为我可以在此之后通过jsdom操作响应。我做body: res.html || ""
所以我可以渲染一个空的布局,如果更方便的话,可以在以后插入正文。
exports.layout = function(req, res, next) {
var layoutPath;
layoutPath = path.join(__dirname, "..", "templates", "layout.jade");
return fs.readFile(layoutPath, "utf8", function(error, jadeText) {
var layoutFunc, locals;
layoutFunc = jade.compile(jadeText, {
filename: layoutPath
});
locals = {
config: config,
title: "",
body: res.html || ""
};
res.html = layoutFunc(locals);
return next(error);
});
};
这里有真正强大的东西。我将HTML字符串转换为jsdom文档对象模型,该模型允许在服务器端进行基于jQuery的转换。下面的toMarkup
函数只允许我在没有jsdom添加的内存中jquery的额外<script>
标记的情况下返回HTML。
exports.domify = function(req, res, next) {
return jsdom.env(res.html, [jqueryPath], function(error, dom) {
if (error) return next(error);
res.dom = dom;
dom.toMarkup = function() {
this.window.$("script").last().remove();
return this.window.document.doctype + this.window.document.innerHTML;
};
return next(error);
});
};
所以这是我做的自定义转换。这可以用真正有效的HTML替换像<flickrshow href="http://flickr.com/example"/>
这样的伪造的DSL标签,否则这将是一个非常讨厌的<object>
样板,我将不得不在每篇博文中复制,如果flickr改变了样板文件他们使用的标记,在许多单独的博客帖子降价文件中修复它将是一种维护痛苦。他们当前使用的样板文件位于flickrshowTemplate
变量中,并包含一些小胡子占位符{URLs}
。
exports.flickr = function(req, res, next) {
var $ = res.dom.window.$;
$("flickrshow").each(function(index, elem) {
var $elem, URLs;
$elem = $(elem);
URLs = $elem.attr("href");
return $elem.replaceWith(flickrshowTemplate.replace(/\{URLs\}/g, URLs));
});
return next();
};
同样嵌入YouTube视频。 <youtube href="http://youtube.com/example"/>
。
exports.youtube = function(req, res, next) {
var $ = res.dom.window.$;
$("youtube").each(function(index, elem) {
var $elem, URL;
$elem = $(elem);
URL = $elem.attr("href");
return $elem.replaceWith(youtubeTemplate.replace(/\{URL\}/, URL));
});
return next();
};
现在我可以根据需要更改标题,添加/删除javascripts或样式表等。这里我在已经渲染布局后设置标题。
postTitle = function(req, res, next) {
var $;
$ = res.dom.window.$;
$("title").text(res.post.title + " | Peter Lyons");
return next();
};
好的,是时候回到最终的HTML了。
exports.undomify = function(req, res, next) {
res.html = res.dom.toMarkup();
return next();
};
现在我们发货了!
exports.send = function(req, res) {
return res.send(res.html);
};
为了将它们整合在一起并明确使用它,我们做
postMiddleware = [
loadPost,
html,
markdownToHTML,
blogArticle,
layout,
domify,
postTitle,
flickr,
youtube,
undomify,
send
]
app.get("/your/uri", postMiddleware);
简明?不。清洁?我认同。灵活?非常。非常快?可能并不快,因为我认为jsdom是你可以做的更重要的事情之一,但我使用它作为静态站点生成器,所以速度是无关紧要的。当然,在中间件链的开头和结尾添加另一个函数将最终的HTML写入静态文件并直接提供它,如果它比相应的降价页面主体内容文件更新,那将是微不足道的。 Stackoverflowers,我很想听听有关这种方法的想法和建议!
答案 1 :(得分:2)
Jade人说将变量传递给过滤器is not supported。我无法理解Peter Lyons的回答,所以我用了这个:
marked = require 'marked'
marked.setOptions
<my options>
app.locals.md = marked
然后在玉:
!= md(<markdown string>)
快速而肮脏。可能不是最理想的,因为它每次运行转换而不缓存结果(我认为),但至少它是有效的。
<强>(编辑)强>
您还可以在浏览器中使用标记来渲染markdown,从服务器卸载一些工作并加快加载速度。