0到Om - 6

Welcome to our next act今天我们将会遇到一些额外的库,这些库可以帮助我们编写出很棒的Om应用程序让我们开始吧!

像往常一样,我强烈推荐阅读上一篇文章如果你还没有这么做。


sablono

在上一篇文章中,我向您展示了应用程序UI的呈现方式:

(dom/div nil
  (header)
  (dom/input 
    #js {:id "new-todo" :ref "newField"
         :placeholder "What needs to be done?"
         :onKeyDown #(enter-new-todo % state owner)})
  (listing state)
  (footer state)))))

正如您可以看到的,DOM / *HTML元素接收属性映射:#js {...}要么没有属性这都是有点尴尬没有设计师会很高兴这就是sablono可以帮助您将代码转换为:

(html
  [:div
    (header)
    [:input
        {:id "new-todo" :ref "newField"
         :placeholder "What needs to be done?"
         :on-key-down #(enter-new-todo % state owner)}]
    (listing state comm)
    (footer state)])))

Ah, much better! Each HTML element is represented by a keyword at the beginning of a vector然后,可选的映射定义其属性其他所有内容必须评估为另一个HTML元素,依此类推所有属性都符合ClojureScript的默认命名约定,并在渲染时自动转换为驼峰版本。

要开始使用sablono,您只需要包含其命名空间和宏:

(ns todomvc.app
  (:require [...]
            [sablono.core :as html :refer-macros [html]])

请注意,通过使用sablono,编译的输出从192 KB(47 KB gzip)增加到201 KB(48 KB gzip)。

秘书

对于路由,意味着应用程序状态和浏览器URL之间的映射,我们可以使用秘书(伟大的名字,对吧?)。

当我们查看名称空间声明时app.cljs我们可以看到路由所需的各种项目:

(ns todomvc.app
  (:require [...]
            [goog.events :as events]
            [secretary.core :as secretary :include-macros true :refer [defroute]])
  (:import  [goog History]
            [goog.history EventType]))

那是非常多的让我们看看我们在这里有什么:

  • 来自秘书,一个叫做的宏defroute和名称空间secretary.core
  • 从谷歌关闭,名称空间goog.events以及元素历史事件类型goog.history

首先,让我们定义路由规则:

(defroute "/"        []       (swap! app-state assoc :showing :all))
(defroute "/:filter" [filter] (swap! app-state assoc :showing (keyword filter)))

有两条路线当第一个匹配,它集:显示进入应用程序的状态所有当第二个比赛设置它的值过滤

But how are the routes wired to the browser? That's where our modules from Google Closure come into play:

(def history (History.))

(events/listen history EventType.NAVIGATE
  (fn [e] (secretary/dispatch! (.-token e))))

(.setEnabled history true)

Google Closure的新实例历史创建,一个新的事件监听器调用秘书调度!功能与当前历史状态(事件的令牌为每个其导航事件字段)。

请注意:自从的setEnabledmethod fires an event for the current location immediately, it has to come after the event listener.

唯一的地方,用户可以导航到不同的url页脚组件

(defn footer [{:keys [todos] :as state}]
  (let [count (count (remove :completed todos))
        sel (-> (zipmap [:all :active :completed] (repeat ""))
                (assoc (:showing state) "selected"))]
    (html
      [:footer {:id "footer" :style (hidden (empty? todos))}
      [:span {:id "todo-count"}
        [:strong count]
        (str " " (pluralize count "item") " left")]
      [:ul {:id "filters"}
        [:li [:a {:href "#/" :class (sel :all)} "All"]]
        [:li [:a {:href "#/active" :class (sel :active)} "Active"]]
        [:li [:a {:href "#/completed" :class (sel :completed)} "Completed"]]]])))

我们可以看到有三种可能的路由状态:所有活性完成对于每个国家都有超链接的页脚触发相应的路线没有更多的!

顺便说一下,来自最后帖子的原始Om应用程序已经包含了秘书编译为JavaScript是192 KB(47 KB gzip)但没有任何路由减少到172 KB(40 KB gzip)。

OM-工具

Prismatic是Om的早期采用者OM-工具它们提供了一系列实用程序,以帮助消除一些烦恼并添加额外的功能开始你需要包括名称空间:

(ns todomvc.app
  (:require [...]
            [om-tools.core :refer-macros [defcomponent]])

这是如何待办事项项目组件看起来像现在:

(defn todo-item [todo owner]
  (reify
    om/IInitState
    (init-state [_]
      ...)

    om/IRenderState
    (render-state [_ state]
      ...)

That's a lot of boilerplate code! om-tools adds a new macro calleddefcomponent这简单了:

(defcomponent todo-item [todo owner]
  (init-state [_]
    ...)

  (render-state [_ state]
    ...)

它使组件定义更小,更易于阅读。

另一个重要特征是Prismatic的整合模式允许声明性数据描述和验证的库我可以写一篇关于它的整篇博文但幸运的是Prismatic已经做到了所以我将在我们的小TodoMVC应用程序中强调它是如何工作的首先,我们需要包括模式库:

(ns todomvc.app
  (:require [...]
            [om-tools.core :refer-macros [defcomponent]])

然后我们为Todo定义一个模式:

(def Todo
    {:id s/Str
     :title s/Str
     :completed s/Bool})

到目前为止,这是非常明显的现在我们可以将模式添加到Om组件参数:

(defcomponent todo-item [todo :- Todo owner]
   ...

:- 去做将参数连接到架构现在,理论上,当创建组件时,验证参数但在此之前我们需要启用验证:

(s/with-fn-validation
  (om/root todo-app app-state
    {:target (.getElementById js/document "todoapp")}))

不幸的是,当我尝试这个时它没有用我还没发现的原因,但这可能是因为通过创建的组件集结所有不确定但是om-tools示例实际上是有效的,所以继续在那里看看它的实际效果。

无论如何,为了得到我们来到这里:让我们明确地验证架构。

(defcomponent todo-item [todo :- Todo owner]
  (init-state [_]
    (s/validate Todo todo)

现在,当我们创建一个新的待办事项的领域completd它导致一个错误一旦待办事项项目组件已创建:

未捕获错误:值与架构不匹配:{:completed missing-required-key,:completd disallowed-key}

这意味着我们可以早些时候捕获错误,防止一些微妙的错误我们都知道和爱从动态语言但是,所有这些改进都需要付出代价:现在生成的JavaScript代码总共增加了264 KB(61 KB gzip)。

图书馆带来了一些其他的东西 - 比如mixins - 所以一定要看看文件


今天就是这样你已经看到几个图书馆可以帮助你获得更多Om的价值。


评论的Disqus