1

我在 github 和 google 群组上问过这个问题。没有结果。所以问题是:

假设我想创建一些可重用的组件。

(defn song-player []
  "display songs and controls"
  (let [current-song (atom {"title" "some title", "url" "some-url"})]
    (fn []
      [:div.player
       [:p "title: " (@current-song "title")]
       [:audio#player-audio
        {:src (str (@current-song "url"))}]
       [:input {:type "button"
                :value "Play/Stop"
                :on-click #(let [player (. js/document (getElementById "player-audio"))]
                             (if (.-paused player)
                               (.play player)
                               (.pause player)))}]])))

假设我想在一页中有几个歌曲播放器。在这种情况下,我无法将 ID(#player-audio) 分配给音频元素,因为该页面将具有重复的 ID。

那么如何在事件处理程序中引用本地组件呢?在这种情况下,如何在 on-click 事件的事件处理程序中引用本地音频元素?

在 react.js 中,我可以为音频组件分配一个引用,并通过 this.refs.XXX 引用。我如何在试剂中做到这一点?谢谢!

4

2 回答 2

1

我认为您尝试执行此操作的方式存在一些问题。特别是您使用原子的方式和您对 getElementById 的使用,这可能会导致试剂/反应出现问题。我的建议是使用原子来保持所有状态(包括音频播放器的状态)。

如果我们假设标题是唯一的并且可以用作键,我会将所有玩家存储为散列的散列。创建一个将歌曲标题作为参数并返回关键字表示的函数可能会很有用,即

(keyword-title "Some Title") => :some-title

{:first-title {:title "First Title"
               :url "http://....."
       :player :stop} ;; could be :stop :pause :play etc
 :another-title {:title "Another Title"
                 :url "some other url"
         :player :stop}}

当您创建一个“新”播放器组件时,您实际所做的是向状态原子添加另一个条目。当您想要交互式按钮/组件时,您可以将它们定义为对状态原子进行操作。然后你定义一个组件,它只呈现你的状态原子中的所有条目。

(defn song-player [title url player-state]
  (let [players (r/atom {})] ;; this will only be called once - first time
    (fn [title url player-state]
  (swap! players assoc (keyword-title title) {:title title
                                              :url url
                          :player player-state})
  [player-component players])))

第一次调用歌曲播放器时,它会创建播放器原子,然后调用匿名函数。这个匿名函数现在是这个组件的渲染函数。这就是为什么匿名函数和父函数具有相同的参数签名很重要的原因。

player-component 获取 player atom,其中包含有关标题的所有状态信息以及与每个标题关联的播放器的状态,遍历 atom 并相应地渲染每个条目

(defn player-component [players]
  (into [:div]
        (for [p (keys @players)]
     ^{:key p} [:div.player
                 [:p "Title: " (get-in @players [p :title])]
         [:audio {:src (get-in @players [p :url])}]
         [:input {:type "button"
                  :value (get-in @players [p :player-state])
              :on-click #(toggle-player-state p players)}]])))

当有人点击按钮时,toggle-player-state 设置新状态

(defn toggle-player-state [player-id players]
  (if (= :stop (get-in @players [player-id :player-state]))
    (swap! players assoc-in [player-id :player-state] :play)
(swap! players assoc-in [player-id :player-state] :stop)))

显然,这只是我的想法,尚未经过测试,实际上是比其他任何东西都更多的伪代码。我不知道 [:audio] 类型扩展到什么,并且可能存在需要满足的限制或您需要设置的其他事件处理程序(例如 :on-complete 或其他)。但是,校长应该是正确的。使用 Reagent/react,我认为目标是避免直接设置/读取 DOM。您管理状态并让试剂/反应完成其余的工作。

于 2015-10-11T08:35:54.197 回答
0

好的,我对任何事情一无所知,但我一直在寻找类似问题的答案,到目前为止我想出的是:

  1. 试剂不存储参考(理论上你可以在你的函数中使用“this-as this”找到它)但是
  2. 您可以使用此处的 component-did-mount 回调中显示的方法将自己的方式加入其中:https ://gist.github.com/danielytics/d4374cd51deec7201250

我敢肯定,现在帮助你已经太晚了,但你永远不知道。

于 2015-09-19T17:43:48.537 回答