4

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

但这只会影响描述元素并忽略名称形式。

绑定本地变量的最佳方法是什么deftemplate

4

2 回答 2

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)))

代码未经测试,但我希望它传达了一种不同的方式来做你需要的事情

于 2012-08-14T08:04:14.483 回答
1

Enlive 的deftemplate宏在 args 向量之后需要一系列标签/内容对([id]在您的示例中是 args 向量)。您不能只将 a 粘贴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库。

于 2012-08-13T04:11:21.923 回答