我是 clojure 和 Web 开发堆栈的新手。我正在尝试使用 enlive 在 HTML 模板中设置值:
(en/deftemplate project-main-page
(en/xml-resource "project-main.html")
[id]
[:#project-name] (en/content (str "Name: " ((get-project id) :name)))
[:#project-desc] (en/content (str "Desc: " ((get-project id) :desc))))
这可以很好地设置我的两个 HTML 元素,但它涉及对我的函数
get-project
的重复调用。目前这只是从本地 map 读取,但最终它会涉及一些外部存储访问,所以我更愿意在这个函数中执行一次。我正在考虑使用
let
:(en/deftemplate project-main-page
(en/xml-resource "project-main.html")
[id]
(let [project (get-project id)]
[:#project-name] (en/content (str "Name: " (project :name)))
[:#project-desc] (en/content (str "Desc: " (project :desc)))))
但这只会影响 description 元素而忽略名称形式。
在
deftemplate
中绑定(bind)本地 var 的最佳方法是什么? 最佳答案
Enlive 的 deftemplate
宏在 args 向量之后需要一系列标签/内容对(在您的示例中, args 向量是 [id]
)。您不能只在其中粘贴 let
,因为宏不期望 let
形式,因此当它进行拼接时,一切都会变得困惑并导致上述行为。
解决此问题的一种方法是编写自己的 deftemplate
宏,该宏允许使用 args 向量中的标识符进行绑定(bind)定义。例子:
(alt/deftemplate project-main-page
(en/xml-resource "project-main.html")
[id]
[project (get-project id)]
[:#project-name] (en/content (str "Name: " (project :name)))
[:#project-desc] (en/content (str "Desc: " (project :desc))))
deftemplate
宏是 template
的简单包装,它使用 snippet*
,这可能是您需要插入更改的地方:(defmacro snippet* [nodes args & forms]
`(let [nodes# (map annotate ~nodes)]
(fn ~args
; You could add let bindings here since args are in scope
(doall (flatmap (transformation ~@forms) nodes#)))))
另一个选项(可能更简单,因为您不必在库代码中乱搞)是向
get-project
函数添加一个间接级别以缓存结果。你可以试试 core.cache 库。关于clojure - 在 deftemplate 中绑定(bind)本地变量以进行激活,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11911010/