我是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
。目前这只是从本地地图读取,但最终它将涉及一些外部存储访问,所以我更喜欢在此功能中执行一次。
我在考虑使用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
中绑定局部变量的最佳方法是什么?
答案 0 :(得分:2)
如果我理解你想要实现的目标;您也可以尝试使用enlive提供的转换宏。
(defn main-page [{:keys [name desc] :as project}]
(en/transformation
[:#project-name] (en/content (str "Name: " name)
[:#project-desc] (en/content (str "Desc: " desc))))
(en/deftemplate project-main-page
(en/xml-resource "project-main.html")
[id]
(main-page (get-project id)))
代码未经测试,但我希望它以不同的方式传达你需要的东西
答案 1 :(得分:1)
Enlive的deftemplate
宏需要args向量之后的一系列标记/内容对(示例中的args向量为[id]
)。你不能只在那里粘贴一个let
,因为宏不期望一个let
形式,所以当它拼接时,一切都搞砸了,导致你上面描述的行为。
您可以解决此问题的一种方法是编写自己的deftemplate
宏,该宏允许使用args向量中的标识符进行绑定定义。例如:
(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库。