defsnippet 仅匹配 html 的特定部分(这就是它采用选择器作为参数的原因),并对其进行转换。deftemplate 获取整个 html,并对其进行转换。此外,defsnippet 返回一个 Clojure 数据结构,而 deftemplates 返回一个字符串向量,因此通常在 deftemplate 中使用 defsnippet。
为了让您了解片段(或选择器)返回的数据是什么样的:
(enlive/html-snippet "<div id='foo'><p>Hello there</p></div>")
;=({:tag :div, :attrs {:id "foo"}, :content ({:tag :p, :attrs nil, :content ("Hello there")})})
在你的情况下,你想要类似的东西:
header.html:
<div id="my-header-root">
...
</div>
Clojure 代码:
(enlive/defsnippet header "path/to/header.html" [:#my-header-root] []
identity)
(enlive/defsnippet footer "path/to/footer.html" [enlive/root] []
identity)
(enlive/deftemplate layout "layout.html" [header footer]
[:head] (enlive/content header)
[:body] (enlive/append footer))
(defroutes home-routes
(GET "/" [] (layout (header) (footer))
片段中使用的标识函数返回它的参数,在本例中是由 :#my-header-root 选择器选择的数据结构(我们不进行任何转换)。如果你想在head.html 中包含所有内容,你可以使用enlive 附带的根选择器步骤。
您可以使用以下方式查看从 defsnippet 生成的 html:
(print (apply str (enlive/emit* (my-snippet))))
我还推荐教程:https ://github.com/swannodette/enlive-tutorial/
和 Brian Marick 的教程,了解更多关于 defsnippet 和 deftemplate 宏如何工作的细节。
最后一个提示,您可以使用 enlive 附带的 sniptest 宏来试验选择器和转换:
(enlive/sniptest "<p>Replace me</p>"
[:p] (enlive/content "Hello world!"))
;= "<p>Hello world!</p>"