我是 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/

10-13 03:22