ClojureScript中如何评估列表并批量定义Material-UI组件?
问题1:评估quoted的def表达式,让one的值变为1
在ClojureScript中,你可以用cljs.core/eval来执行这个quoted的定义表达式。和Clojure不同的是,CLJS的eval受编译环境影响(比如高级优化模式下会有更多限制),但在开发环境或者简单场景下完全够用。
直接运行这段代码就能实现需求:
(def defining-list `(def one 1)) (cljs.core/eval defining-list) ;; 测试验证,会输出1 (println one)
注意:eval默认会在当前命名空间执行,所以one会被定义在你当前的命名空间下。如果需要在特定命名空间执行,你可以先切换命名空间或者指定命名空间来评估。
问题2:批量定义Material-UI组件(无需宏)
你之前的doseq代码只是生成了def表达式的列表,但没有实际执行它们。不用宏也不用eval的话,推荐用cljs.core/intern来动态在当前命名空间创建变量——这是CLJS里更安全、更符合惯用写法的动态定义方式,还能避免eval带来的兼容性和安全问题。
这里是完整的实现代码:
;; 确保已经引入reagent的adapt-react-class (require '[reagent.core :as r]) (def material-ui-tags '[AppBar Avatar Backdrop]) (doseq [component material-ui-tags] (let [;; 把组件名转成kebab-case的符号(比如AppBar → app-bar) kebab-name (-> (name component) (clojure.string/replace #"([A-Z])" "-$1") clojure.string/lower-case (clojure.string/replace #"^-" "")) kebab-symbol (symbol kebab-name) ;; 获取MaterialUI上的原生React组件 raw-component (aget js/MaterialUI (name component)) ;; 用reagent适配成CLJS可用的组件 cljs-component (r/adapt-react-class raw-component)] ;; 在当前命名空间定义这个符号,绑定到适配后的组件 (intern *ns* kebab-symbol cljs-component)))
如果你的项目里已经有现成的->kebab-case函数(比如来自clojure.string或者第三方工具库),可以直接替换掉上面的字符串处理逻辑,代码会更简洁:
(doseq [component material-ui-tags] (let [kebab-symbol (symbol (->kebab-case component)) cljs-component (r/adapt-react-class (aget js/MaterialUI (name component)))] (intern *ns* kebab-symbol cljs-component)))
执行完这段代码后,你就能直接使用app-bar、avatar、backdrop这些符号了,和手动逐个定义的效果完全一致。
内容的提问来源于stack exchange,提问作者m-arch
相关产品推荐
相关产品推荐

