使用 Om,从嵌套映射生成嵌套 div
Using Om, Generate Nested divs From a Nested Map
假设我有以下地图:
(def m {"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}})
我需要这样渲染:
(om.dom/div #js {} "a"
(om.dom/div #js {} "d")
(om.dom/div #js {} "e"))
(om.dom/div #js {} "b"
(om.dom/div #js {} "f")
(om.dom/div #js {} "g"
(om.dom/div #js {} "h")
(om.dom/div #js {} "i")))
(om.dom/div #js {} "c")
我该怎么做?我搞砸了 clojure.walk
,但无法让它先在叶子上调用 om.dom/div
,然后是直接父级,等等。
我认为解决方案可能涉及在给定子映射的 vals
上映射递归函数。它会将地图分开,直到它看到 叶子 ,然后冒泡 om.dom/div
调用返回地图。
到目前为止我有这个功能:
(defn build-tree [data]
(apply dom/div #js {}
(->> (clojure.walk/postwalk
#(cond (map? %) (vec %)
(vector? %) %
(string? %) %) data)
(clojure.walk/postwalk
#(if (and (vector? %) (string? (first %)))
(apply dom/div #js {} %) %)))))
这导致:
在检查器中使用这个:
生成嵌套 dom/ul
和 dom/li
元素的奖励积分..
由以下代码生成的 DOM-结构看起来与您正在寻找的非常接近,除了子节点(即使没有任何子节点)被包裹在 div
,这应该很容易修复:
(defn tree-component
[tree]
(apply dom/div nil
(keep (fn [[k v]]
(when k
(dom/div nil k
(tree-component v))))
tree)))
(defn app-view
[data owner]
(reify
om/IRender
(render [_]
(tree-component
{"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}}))))
clojure.walk
很棒,但有时会变得更难。我有这个:
(defn recursive-component [el]
(cond
(empty? el) nil
(vector? el) (apply dom/div nil
(first el)
(recursive-component (second el)))
(map? el) (map recursive-component el)))
(defn main-component [data owner]
(om/component
(apply dom/div nil "Main"
(recursive-component m))))
对于ul
和li
:
(defn recursive-component [el]
(cond
(and (vector? el) (empty? (second el)))
(dom/li nil (first el))
(vector? el) (apply dom/ul nil
(first el)
(recursive-component (second el)))
(map? el) (map recursive-component el)))
但它显示为 li
{:c {}}
元素。
解决此类问题时,有时在 REPL 中生成类似于所需调用树的树结构会很有帮助。一旦结果看起来不错,将其转换为实际的调用树通常很简单。
例如,这里有一个函数可以为您的示例生成 om.dom/div
调用树;要在 ClojureScript 中使用,请按照评论中的说明进行调整:
(defn div [m]
(for [[k v] m]
;; replace with (apply om.dom/div #js {} k (div v)) in CLJS
(list* 'om.dom/div {} k (div v))))
调用示例:
(div {"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}})
上面的输出:
;; in CLJS, you'll want to use this as the ... in
;; (apply create-container-component initial-args ...)
((om.dom/div {} "a"
(om.dom/div {} "d")
(om.dom/div {} "e"))
(om.dom/div {} "b"
(om.dom/div {} "f")
(om.dom/div {} "g"
(om.dom/div {} "h")
(om.dom/div {} "i")))
(om.dom/div {} "c"))
假设我有以下地图:
(def m {"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}})
我需要这样渲染:
(om.dom/div #js {} "a"
(om.dom/div #js {} "d")
(om.dom/div #js {} "e"))
(om.dom/div #js {} "b"
(om.dom/div #js {} "f")
(om.dom/div #js {} "g"
(om.dom/div #js {} "h")
(om.dom/div #js {} "i")))
(om.dom/div #js {} "c")
我该怎么做?我搞砸了 clojure.walk
,但无法让它先在叶子上调用 om.dom/div
,然后是直接父级,等等。
我认为解决方案可能涉及在给定子映射的 vals
上映射递归函数。它会将地图分开,直到它看到 叶子 ,然后冒泡 om.dom/div
调用返回地图。
到目前为止我有这个功能:
(defn build-tree [data]
(apply dom/div #js {}
(->> (clojure.walk/postwalk
#(cond (map? %) (vec %)
(vector? %) %
(string? %) %) data)
(clojure.walk/postwalk
#(if (and (vector? %) (string? (first %)))
(apply dom/div #js {} %) %)))))
这导致:
在检查器中使用这个:
生成嵌套 dom/ul
和 dom/li
元素的奖励积分..
由以下代码生成的 DOM-结构看起来与您正在寻找的非常接近,除了子节点(即使没有任何子节点)被包裹在 div
,这应该很容易修复:
(defn tree-component
[tree]
(apply dom/div nil
(keep (fn [[k v]]
(when k
(dom/div nil k
(tree-component v))))
tree)))
(defn app-view
[data owner]
(reify
om/IRender
(render [_]
(tree-component
{"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}}))))
clojure.walk
很棒,但有时会变得更难。我有这个:
(defn recursive-component [el]
(cond
(empty? el) nil
(vector? el) (apply dom/div nil
(first el)
(recursive-component (second el)))
(map? el) (map recursive-component el)))
(defn main-component [data owner]
(om/component
(apply dom/div nil "Main"
(recursive-component m))))
对于ul
和li
:
(defn recursive-component [el]
(cond
(and (vector? el) (empty? (second el)))
(dom/li nil (first el))
(vector? el) (apply dom/ul nil
(first el)
(recursive-component (second el)))
(map? el) (map recursive-component el)))
但它显示为 li
{:c {}}
元素。
解决此类问题时,有时在 REPL 中生成类似于所需调用树的树结构会很有帮助。一旦结果看起来不错,将其转换为实际的调用树通常很简单。
例如,这里有一个函数可以为您的示例生成 om.dom/div
调用树;要在 ClojureScript 中使用,请按照评论中的说明进行调整:
(defn div [m]
(for [[k v] m]
;; replace with (apply om.dom/div #js {} k (div v)) in CLJS
(list* 'om.dom/div {} k (div v))))
调用示例:
(div {"a" {"d" {}
"e" {}}
"b" {"f" {}
"g" {"h" {}
"i" {}}}
"c" {}})
上面的输出:
;; in CLJS, you'll want to use this as the ... in
;; (apply create-container-component initial-args ...)
((om.dom/div {} "a"
(om.dom/div {} "d")
(om.dom/div {} "e"))
(om.dom/div {} "b"
(om.dom/div {} "f")
(om.dom/div {} "g"
(om.dom/div {} "h")
(om.dom/div {} "i")))
(om.dom/div {} "c"))