1

我创建了一个脚注系统,使用建立在语义 ui(仅限 css)之上的试剂(对于任何阅读 javascript 的人来说,这是一个 clojurescript 包装器),它处理点击和键盘事件以及鼠标悬停。除了一件小事之外,一切都完美无缺:它只正确处理一次键盘事件,然后就失败了。

代码在底部,但有点复杂,所以在展示之前我会解释一下。

所有原子都是试剂原子。入口点是footnote,它是一个获取脚注文本以及页面标记(不相关)的组件。

footnote及其下游功能:

  1. 从全局状态中获取一个计数器值,将其递增,并将其用作脚注的数字,

  2. 创建一些局部状态(试剂原子)来控制包含文本的模态是否可见,并将其初始化为 false,

  3. 将带有工具提示的上标脚注标识符附加到文本(用于鼠标悬停)

  4. 将单击事件处理程序附加到该脚注标识符,它将模态可见性原子设置为 true,并且

  5. 将键盘事件侦听器附加到全局窗口,当按下数字时,它将模态可见性原子设置为 true。

然后,当模态可见性原子为真时:

  1. 另一个键盘事件侦听器附加到全局窗口,它将模态可见性原子设置为 false。

  2. 一个点击监听器附加到模态本身(在一些地方,因为我在 DOM 上很烂,并且不相信我有能力找出一个可能点击的位置),还将模态可见性原子设置为 false。

我认为应该发生的事情:

在渲染时,鼠标悬停应显示带有文本的工具提示,单击脚注编号或按键盘上的脚注编号应打开带有文本的模式。当模式打开时,单击任意位置应将其关闭,按任意键也应如此。关闭模式后,用户应该能够通过单击或按键盘上的数字再次打开它。

实际发生的情况:

除了上一段中的斜体字之外的所有内容。相反,在关闭模式后,如果我按相应的键再次打开它,模式不会重新打开(单击仍然有效)。

当我包装密钥处理函数调试日志调用时,它会将“true”记录到控制台,表明原子处于预期状态。

有趣的是,通过点击刷新或仅通过渲染重新渲染整个虚拟“页面”(即包含脚注组件的更高级别的组件 - 这是一个具有虚拟页面作为反应/试剂组件的单页面站点)另一个包含不同/没有脚注的“页面”组件然后重新渲染原始的“页面”组件,似乎重置了我得到的任何一种不稳定的状态,并且键盘触发器再次工作。

相关地,我在全局窗口上挂着其他键盘事件,但没有使用与脚注相同的击键。特别是,我有用于在“页面”之间导航的键盘事件(h 表示主页等)。有趣的是,如果我使用其他键之一关闭模式,它工作得很好——很可能是因为其他键首先重新呈现其他页面之一,然后根据我的强制重新呈现呈现原始页面?

下面的代码(从我最初发布此问题时修改)试图通过重新渲染原始页面(即 )来利用最后一个怪癖navload,但没有骰子(可能是因为 react 足够聪明,不会重新渲染页面,如果它已经在那里了吗?)。

我还尝试通过首先渲染一个虚拟页面然后立即再次渲染原始页面来强制在关闭功能中重新渲染,但没有骰子——这实际上使事情变得更糟(重新渲染不再重置键盘脚注容量.)

最后,我尝试了包括reagent/force-update-allinclose-modal以及this issue中的“强制”技巧。两者都没有导致行为的任何改变。

其他可能相关的信息:

listen函数来自 google 闭包库 ( goog.events),而不是普通的 javascript。不知道这是否具有奇怪的语义或可能导致此问题的东西。

有没有人有任何精彩的见解?谢谢!:-)

(defn footnote-flag [num ratom text]
  [:sup {:data-tooltip text
         :on-click #(reset! ratom true)}
         (str "(" num ") ")])

(defn close-modal [ratom page]
  (cond
    (= @ratom true)
    (do
      (reset! ratom false)
      (navload page))))

(defn modal-content [text ratom page]
  (when @ratom
    (do
      (listen js/window "keypress" #(close-modal ratom page))
      [:span.ui.dimmer.modals.page.transition.visible.active
       {:on-click #(close-modal ratom page)}
       [:span.ui.standard.basic.modal.transition.visible.active.scrolling
        {:on-click #(close-modal ratom page)}
        [:p text]]])))

(defn handle-footnote-key [key-event num page ratom]
  (let [keypress (.-keyCode key-event)]
    (cond
      (and  (= (+ 48 num) keypress) (= page @stdio.nav.curpage))
      (reset! ratom true))))

(def footnote-counter (atom 0))

(defn footnote [text page]
  (do
    (swap! footnote-counter inc)
    (let [modal-state (atom false)
          num @footnote-counter]
      (listen js/window "keypress" #(handle-footnote-key % num page modal-state))
      (fn [text]
        [:span
         [footnote-flag num modal-state text]
         [modal-content text modal-state page]]))))
4

2 回答 2

1

footnote-counter一个clojure.core/atom什么时候应该是一个reagent.core/atom

于 2016-07-03T23:15:11.030 回答
1

经过一番摸索,并在上面迈克汤普森的提示的帮助下,一个解决方案出现了。

将键事件侦听器移动到返回的渲染函数而不是外部函数似乎会产生正确的行为。老实说,我不太清楚为什么,并且会喜欢任何见解...

(defn footnote [text page]
  (do
    (swap! footnote-counter inc)
    (let [modal-state (atom false)
          num @footnote-counter]
      (fn [text]
        (do
          (listen js/window "keypress" #(handle-footnote-key % num page modal-state))
         [:span
          [footnote-flag num modal-state text]
          [modal-content text modal-state page]])))))
于 2016-07-04T02:51:47.783 回答