defsn-p 仅匹配 html 的特定部分(这就是为什么它将选择器作为参数),并对其进行转换。 deftemplate 获取整个 html,并对其进行转换。另外,defsn-p 返回一个 Clojure 数据结构,而 deftemplates 返回一个字符串向量,所以 deftemplate 中通常使用 defsn-p。
让您了解 sn-p(或选择器)返回的数据是什么样的:
(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))
sn-ps 中使用的标识函数返回它的参数,在本例中是由 :#my-header-root 选择器选择的数据结构(我们不进行任何转换)。如果你想在 head.html 中包含所有内容,你可以使用 enlive 附带的根选择器步骤。
您可以使用以下方式查看从 defsn-p 生成的 html:
(print (apply str (enlive/emit* (my-snippet))))
我也推荐教程:https://github.com/swannodette/enlive-tutorial/
还有一篇由 Brian Marick 撰写的关于 defsn-p 和 deftemplate 宏如何工作的更多细节。
最后一个提示,您可以使用 enlive 附带的 sniptest 宏来试验选择器和转换:
(enlive/sniptest "<p>Replace me</p>"
[:p] (enlive/content "Hello world!"))
;= "<p>Hello world!</p>"