这篇文章演示一个用 ClojureScript 和 Respo 写一个最简单的计数器, 作为一个 MVC 的例子.
我会对代码做一些说明. 完整的代码请访问 GitHub: https://github.com/Respo/minimal-tiny-app
首先, 需要一个 HTML 文件用来加载 main.js
, 然后还有有个 div.app
作为组件挂载的节点:
<html>
<head>
<title>Tiny App</title>
<meta charset="utf8" />
</head>
<body>
<div class="app" />
<script src="/main.js" />
</body>
</html>
然后我们来写 ClojureScript 代码, 写在 main.cljs
当中. 开头是引用相关的函数:
(ns app.main
(:require [respo.macros :refer [defcomp <> div span button]]
[tiny-app.core :refer [create-tiny-app->]]))
作为 MVC 当中的 M, 这里使用的是一个 map, 注意 :states {}
是默认存储状态树所需要的:
(def store {:count 0, :states {}})
然后是一个 updater
函数, 一个纯函数, 用来接收 Action 和 data, 对 store
做纯函数的不可变数据结构的更新:
(defn updater [store op op-data]
(case op
:inc (update store :count inc)
store))
MVC 当中的 V 部分, 在 Respo 里是一个组件, 这里绑定了一个简单的点击事件, 点击时发出 :inc
这个 Action:
(defcomp comp-container [store]
(div {}
(button {:inner-text "inc"
:style {:border :none
:outline :none
:background-color "#aac"
:display :inline-block
:color :white
:border-radius "0px"
:cursor :pointer
:font-size 20}
:on {:click (fn [e dispatch! mutate!]
(dispatch! :inc nil))}})
(<> (:count store))))
有了 MVC 对应的部分, 就可以使用 create-tiny-app->
定义一个 app 了. 实际上这是一个 macro, 但是这里的用法就像一个函数:
(def app
(create-tiny-app->
{:model store
:updater updater
:view comp-container
:mount-target (.querySelector js/document ".app")
:ssr? false
:show-ops? true}))
最后要绑定一下 app 如何启动, 以及如何进行热替换:
(def reload! (:reload! app))
(set! (.-onload js/window) (:start-app! app))
编译这个应用需要用 shadow-cljs, 以及它的配置文件 shadow-cljs.edn
:
{:source-paths ["src"]
:dependencies [[respo "0.6.6"]
[respo/tiny-app "0.2.0-alpha"]]
:builds {:app {:target :browser
:output-dir "target/"
:asset-path "."
:modules {:main {:entries [app.main]}}
:devtools {:after-load app.main/reload!}}}}
这个配置的意思是会把 src/
当中的项目代码编译到 target/
当中, 模块的名字是 main
.
最后用 http-server
命令启动相应的 index.html
和 main.js
就好了. 大致目录结构是:
src/
app/main.cljs
target/
index.html
main.js
完整的项目请访问: