不久以前,我一直在寻找在ClojureScript中进行客户端路由和模板化的好方法。 我研究了使用ClojureScript中的一堆JavaScript框架,其中Angular可能给出了最有希望的结果,但仍然感到有些肮脏和沉重。 我什至基于Pedestal和goog.History
实现了自己的路由/模板机制 ,但仍然感觉有些错误。
事情发生了变化,如今,关于基于React的库(如Reagent和Om)引起了很多议论。 我怀疑带有大量“本机” ClojureScript库的React可能是更好的选择。
在到达那里之前,我想重新回顾一下路由和模板。 让我们看看如何将两个不错的库结合在一起:路由秘书和模板模板Enfocus 。
假设我们的应用程序有两个屏幕,它们占据了整个页面。 到目前为止,还没有各种“片段”可以构成页面。 当我们导航到/#/add
时希望看到一个页面,而在/#/browse
希望看到另一个页面。 “浏览”页面将更加高级,并支持路径参数。 例如,对于/#/browse/Stuff
我们想解析“ Stuff”并显示带有该单词的标题。
主要HTML可能如下所示:
<!DOCTYPE html>
<html>
<body>
<div class="container-fluid">
<div id="view">Loading...</div>
</div>
<script src="js/main.js"></script>
</body>
</html>
然后,我们有两个模板。
add.html:
<h1>Add things</h1>
<form>
<!-- boring, omitted -->
</form>
Browse.html:
<h1></h1>
<div>
<!-- boring, omitted -->
</div>
现在,我们要做的就是在位置更改时用模板之一填充#view
上的#view
元素。 完整的代码如下。
(ns my.main
(:require [secretary.core :as secretary :include-macros true :refer [defroute]]
[goog.events :as events]
[enfocus.core :as ef])
(:require-macros [enfocus.macros :as em])
(:import goog.History
goog.History.EventType))
(em/deftemplate view-add "templates/add.html" [])
(em/deftemplate view-browse "templates/browse.html" [category]
["h1"] (ef/content category))
(defroute "/" []
(.setToken (History.) "/add"))
(defroute "/add" []
(em/wait-for-load
(ef/at
["#view"] (ef/content (view-add)))))
(defroute "/browse/:category" [category]
(em/wait-for-load
(ef/at
["#view"] (ef/content (view-browse category)))))
(doto (History.)
(goog.events/listen EventType/NAVIGATE #(secretary/dispatch! (.-token %)))
(.setEnabled true))
这是怎么回事?
- 我们定义了两个Enfocus模板。
view-add
很简单,只是返回整个模板。view-browse
更有趣:给定类别名称,通过用类别名称替换h1
标签的内容来更改模板。 - 然后,我们定义秘书路线以实际使用这些模板。 他们现在所做的
#view
用模板替换#view
元素的内容。 如果使用“浏览”路由,它将通过路径解析的类别名称传递到模板。 - 有一个默认路由从
/
重定向到/add
。 它不会导致example.com/add
,而只会设置片段:example.com/#/add
。 - 最后,我们将秘书插入
goog.History
。 我不知道为什么不在包装盒中,但是它很简单。 - 请注意,在历史记录处理程序中有
em/wait-for-load
调用。 如果使用AJAX调用加载模板,则对于Enfocus是必要的。
就这样,非常简单明了。
更新:修复了em/wait-for-load
,这非常感谢Adrian!