Web applications ClojureScript&Om:编写document.hash的最佳实践

Web applications ClojureScript&Om:编写document.hash的最佳实践,web-applications,routing,clojurescript,om,Web Applications,Routing,Clojurescript,Om,我有一个你好,世界!ClojureScript中的应用程序,使用从Chestnut lein模板生成的Om 目标是将其设置为: document.location.hash值反映对:路由应用程序状态向量的更改。 :route app状态向量反映对document.location.hash值的更改。 当:路由应用程序状态更改时,应用程序将重新呈现。 请注意:route应用程序状态向量是应用程序当前状态的唯一真实来源。改变它的一种机制是用户修改url 在何处以及如何将此行为附加到Om 这是我的你好

我有一个你好,世界!ClojureScript中的应用程序,使用从Chestnut lein模板生成的Om

目标是将其设置为:

document.location.hash值反映对:路由应用程序状态向量的更改。 :route app状态向量反映对document.location.hash值的更改。 当:路由应用程序状态更改时,应用程序将重新呈现。 请注意:route应用程序状态向量是应用程序当前状态的唯一真实来源。改变它的一种机制是用户修改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。最终,这将是一个单页应用程序,使用哈希导航进行视图更改


这让我感觉很不舒服,因为必须在update location hash的render函数中返回一个DOM元素,它除了满足render函数的要求之外没有任何其他用途。

好的,我知道我需要什么了。我觉得它很干净,很管用。 为了完整性,我只需要添加一个检查散列的页面加载类型侦听器和一个呈现散列状态更改的呈现器。基于我前面的代码,这应该是非常直接的

(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"))}))