使用Reagent时,DOM的更新完全交由Reagent处理,但如果我们想要自定义DOM解析,比如使用第三方JavaScript库时该如何做呢?本文以使用Highchart绘制股票资金流图表为例,演示如何在保留Reagent优势的同时使用第三方库。
首先定义需要用到的状态变量。注意要用defonce
。
(defonce cashflow-state (atom []))
定义承载图表的div元素:
(defn chart-holder [dom-id & _]
(fn [dom-id & _]
[:div {:id dom-id}]))
定义HighChart的参数,
(defn hs-options [xs]
(let [dates (map :date xs)
diff (/ (- (reduce + (map :buy xs)) (reduce + (map :sell xs)) ) 1000.0)
xts (map :ts xs)]
{:chart {:zoomType "x"}
:title "资金流"
:xAxis {:categories dates :crosshair true}
:yAxis [{:title "资金流"}
{:title "中性盘"}]
:tooltip {:shared true}
:series [{:type :column :name (str "差额 [" diff "k]") :data (map #(- (:buy %) (:sell %)) xs)}
{:type :spline :name "中性盘" :data (map #(% :neutral %) xs) :yAxis 1}]}))
用reagent/create-class
创建组件。因为hs-options
返回的是Clojure数据结构,传给Highcharts.charts
时不要忘记用clj->js
转换为JavaScript对象。
(defn cashflow-chart [dom-id]
(let [update-me(fn []
(let [chart (.chart
js/Highcharts
dom-id
(clj->js (hs-options @cashflow-state)))]
(.setSize chart 800 300)))]
(reagent/create-class
{:reagent-render #(chart-holder dom-id @cashflow-state)
:component-did-update update-me
:component-did-mount update-me})))
现在把图表显示出来:
(reset! cashflow-state hidden-cashflow-data)
(swap! cashflow-state conj {:buy 109650234, :sell 134822895, :neutral 4267390, :date "2017-01-24", :ts 1485187200000} )
(swap! cashflow-state conj {:buy 43788438, :sell 61379570, :neutral 1130792, :date "2017-01-25", :ts 1485273600000})
[cashflow-chart "myklipse-chart1"]
细心的同学会发现在cashflow-chart
函数的定义里,传递给:regent-render
匿名函数的参数@cashflow-state
似乎是多余的,也就是这一行:
:reagent-render #(chart-holder dom-id @cashflow-state)
这样做是为了保证在cashflow-state
的状态改变时,reagent能收到通知,以便更新DOM。
参考
Timothy Pratley的文章对Reganet的使用作了深入的解说,值得仔细阅读。