我有一个"你好,世界!"使用Om的ClojureScript中的应用程序(从" Chestnut" lein模板生成)。
目标是让它设置为:
document.location.hash
值反映了对(:route app-state)
向量的更改。(:route app-state)
向量反映了对document.location.hash
值的更改。(:route app-state)
更改时,应用重新呈现。请注意,我打算将(:route app-state)
向量作为应用程序关于应用程序当前状态的唯一事实来源。改变它的一种机制是用户修改URL。
我应该在何处以及如何将此行为附加到Om?
这是我的"你好,世界!"应用
(ns demo.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[clojure.string :as string]))
(defonce app-state (atom {:text "Hello, World!"
:route ["some" "app" "route"]}))
(defn update-location-hash [app owner]
(reify
om/IRender
(render [_]
(set! js/window.location.hash
(string/join "/" (flatten ["#" (:route app)])))
(dom/div nil ""))))
(om.core/root
update-location-hash
app-state
{:target (. js/document (getElementById "app"))})
(defn main []
(om/root
(fn [app owner]
(reify
om/IRender
(render [_]
(dom/h1 nil (:text app)))))
app-state
{:target (. js/document (getElementById "app"))}))
这样就可以在页面加载时成功写入document.hash
。最终,这将是一个单页应用程序,它使用哈希导航来进行视图更改。
由于必须在(render )
update-location-hash
函数中返回一个除了满足{{功能。
答案 0 :(得分:0)
好的,我想出了我需要的东西。它对我来说似乎很干净而且很有效。 为了完整起见,我只需要添加一个页面加载类型的侦听器来检查哈希值和渲染器,它将状态更改呈现给哈希值。这应该是非常简单的(基于我之前的代码)。
(ns demo.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [goog.events :as events]
[goog.events.EventType :as EventType]
[cljs.core.async :as async :refer [>! <! put! chan]]
[om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[clojure.string :as string]))
;; Not sure what this does.
(enable-console-print!)
(defn listen
"An event listener factory. Given an element and an event type, return a
channel that can be polled for event outputs."
[el type]
(let [out (chan)] (events/listen el type #(put! out %)) out))
(defonce app-state
(atom {:text "Hello, World!"
:mouse [0 0]
:route ["some" "app" "route"]}))
(defn url-to-route
"Given a url, parse the hash value as an app route. In general, the
resultant route has these properties:
* route components are split on a solidus
* empty components are ignored (nill or all-whitespace)
A route like this:
['foo' 'bar' 'baz']
will be produced by all of the following urls (and others):
http://my-app.com/#/foo/bar/baz
http://my-app.com/#foo/bar/baz
http://my-app.com/#/foo// /bar//baz
http://my-app.com/#/ / / /foo/bar////baz"
[url]
;; Split the url at a hash followed by zero or more slashes and
;; whitespace. Then take anything after the hash and split it on one or
;; more slashes (ignoring whitespace).
(string/split (second (string/split url #"#[/\s]{0,}" 2)) #"[/\s]+"))
(defn layout
"The central application layout component. This registers global event
listeners and renders the application's root DOM nodes."
[app owner]
(reify
om/IWillMount
(will-mount [_]
;; Handle various events. When an event is triggered, format the
;; response.
(let [;; Listen for changes to the mouse position
mouse-chan (async/map
(fn [event] [(.-clientX event) (.-clientY event)])
[(listen js/window EventType/MOUSEMOVE)])
;; Listen for changes to the URL's hash
hash-chan (async/map
(fn [event] (url-to-route (-> event .-event_ .-newURL)))
[(listen js/window EventType/HASHCHANGE)])]
;; Watch the stream and update the application state whenever
;; anything changes.
(do
(go (while true (om/update! app :route (<! hash-chan))))
(go (while true (om/update! app :mouse (<! mouse-chan)))))))
om/IRender
(render [_]
(dom/div
nil
(dom/div nil (when-let [route (:route app)] (pr-str (:route app))))
(dom/div nil (when-let [pos (:mouse app)] (pr-str (:mouse app))))
(dom/h1 nil (:text app))))))
(defn main []
(om/root
layout
app-state
{:target (. js/document (getElementById "app"))}))