0到Om - Act 6

欢迎来到我们的下一个节目。今天我们将看到一些额外的库,它们将帮助我们编写出色的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)])))

啊,更好的!每个HTML元素由向量开头的关键字表示。然后,可选映射定义其属性。其他所有元素都必须计算为另一个HTML元素,等等。所有属性都匹配ClojureScript的默认命名约定,并在呈现时自动转换为大小写混合的版本。

要开始使用sablono,您只需要包括它的名称空间和宏:

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

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

秘书

路由,表示应用程序状态和浏览器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以及元素历史EventTypegoog.history

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

defroute "/"[](交换!显示:all))(defroute "/:filter" [filter](交换!app状态assoc:显示(关键词筛选)

有两条路线。当第一个匹配时,它集:显示应用程序状态的输入所有。当第二个匹配时,将其设置为过滤器

但是路由是如何连接到浏览器的呢?这就是我们来自谷歌闭包的模块发挥作用的地方:

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

谷歌闭包的新实例历史被创建,一个新的事件监听器调用secretary's调度!函数具有当前历史状态(事件的)令牌每个导航事件。

请注意:自setEnabled方法立即为当前位置触发事件,它必须在事件侦听器之后。

用户可以导航到不同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 gzipped),但如果没有任何路由,它会缩小到172 KB (40 KB gzipped)。

om-tools

Prismatic是Om和with的早期采用者om-tools它们提供了一组实用程序来帮助消除一些烦恼并添加额外的功能。首先,您需要包含名称空间:

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

下面是如何待办事宜组件看起来像现在:

(defn todo-item [todo owner])(具象化om/IInitState (init-state[_]…)

这是很多样板代码!工具添加了一个名为defcomponent这给它带来了简单:

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

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

另一个重要的特点是棱镜的整合模式允许声明式数据描述和验证的库。我可以写一整篇关于它的博客,但幸运的是移动已经做。我将强调一下它在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))

现在,当我们用字段创建一个新的Todo时completd它会导致一个错误待办事宜组件创建:

未捕获错误:值不匹配模式:{:已完成的丢失请求键,:completd disallowed-key}

这意味着我们可以更早地捕捉错误,并防止动态语言中一些我们都知道并喜爱的细微错误。所有的进步都是有代价的,但是:生成的JavaScript代码现在总共是264 KB (61 KB gzipped)。

这个库还提供了其他一些东西—比如mixin—所以请确保查看文档


今天就到这里。您已经了解了一些库如何帮助您从Om中获得更多的价值。


评论的Disqus