6

是否有使 DOM 看起来像 Clojure 数据结构的 Clojurescript 库?我发现了一些像 Enfocus 这样的库,它们可以进行某些类型的 DOM 操作,但我想要的是能够像这样对待 DOM:

(get dom id) - returns element called id in dom
(get dom id create-fn) - return element if exists, otherwise creates it
(update-in dom [:body this that] update-fn) - set attribute on a DOM element 
(assoc parent-element id child-element) - associate child element with parent
(conj parent child) - append child element to parent element

等等

4

1 回答 1

4

Clojure 数据结构都是持久的,但在您的示例中,您似乎想要产生副作用(即,命中 DOM 以更改它)。

这是一种非常程序化/命令式的方法,因此可能值得退后一步,以更实用的方式重新表述问题。我个人的理念是将“视图视为数据”,并使用 Clojure 的持久数据结构对其进行建模,直到我需要渲染的最后一分钟。

你熟悉小嗝嗝吗?这个想法是使用纯向量和地图来表示 HTML 或 SVG DOM:

[:div {:with "attribute"} "and" [:span "children"]]

您可以通过组合普通的旧 Clojure 函数来构建它。在 Clojure 中,您可以将其渲染为 HTML(使用原始的 Hiccup 库),但至少有两个 ClojureScript 库可以直接渲染到(可能存在的)DOM 结构中。 Crate是 Hiccup 的一个封闭端口,Singult具有一些额外的语义,例如受 D3.js 启发的数据绑定(Singult 实际上是用 CoffeeScript 编写的,因此它可以从纯 JavaScript 中使用,并且比 Crate 更快)。

我的C2库在 Singult 之上构建数据绑定语义,以使 DOM 与底层数据保持同步。考虑这个 TODO 列表模板:

(bind! "#main"
        [:section#main {:style {:display (when (zero? (core/todo-count)) "none")}}
        [:input#toggle-all {:type "checkbox"
                            :properties {:checked (every? :completed? @core/!todos)}}]
        [:label {:for "toggle-all"} "Mark all as complete"]
        [:ul#todo-list (unify (case @core/!filter
                                :active    (remove :completed? @core/!todos)
                                :completed (filter :completed? @core/!todos)
                                ;;default to showing all events
                                @core/!todos)
                              todo*)]])

(取自C2 TodoMVC 实现)。诸如是否选中“全选”框之类的事情直接来自基础数据(存储在原子中)。每当该数据更改时,模板将重新运行并自动更新 dom。

基本思想是构建从应用程序数据到 Hiccup 数据结构的正向映射,然后让库负责同步 DOM(添加/删除子项、属性等)。如果您不必关心 DOM 的状态(是否已经添加?我需要切换一些类吗?),那么很多附带的复杂性就会消失。

于 2012-07-02T14:48:32.910 回答