首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ClojureScript中,只有当‘:on-双击事件’事件未触发时,才会触发延迟`:on-click`‘事件。

在ClojureScript中,只有当‘:on-双击事件’事件未触发时,才会触发延迟`:on-click`‘事件。
EN

Stack Overflow用户
提问于 2018-02-25 01:51:17
回答 2查看 1.3K关注 0票数 3

延迟:on-click事件以查看是否触发:on-double-click事件的简单方法是什么?

代码语言:javascript
复制
[:div {:on-click (fn [e]
                   ;; listen to double-click event, within 500ms, 
                   ;; if so on-double-click-fn, 
                   ;; if not, on-click-fn
                  )
       :on-double-click (fn [e] 
                          ;; on-click-fn
                         )}]

谢谢!

第一次尝试:

代码语言:javascript
复制
(defn sleep [timeout]
  (let [maxtime (+ (.getTime (js/Date.)) timeout)]
    (while (< (.getTime (js/Date.)) maxtime))))

[:div {:on-click (fn [e] (sleep 500) (print "single-clicked"))
       :on-double-click (fn [e] (print "double-clicked"))}]

第二次尝试:

代码语言:javascript
复制
(def state (atom {:click-count 0}))

(defn handle-click [e click-fns-map]
  (swap! state update :click-count inc)
  (sleep 500)
  (let [click-count (get @state :click-count)]
    (swap! state assoc :click-count 0)
    (cond
      (= click-count 1) ((:on-single-click click-fns-map) e)
      (> click-count 1) ((:on-double-click click-fns-map) e)))))

[:div 
 {:on-mouse-down 
  (fn [e]
    (handle-click e {:on-single-click #(print "single-click")
                     :on-double-click #(print "double-click")}))}]

 ;;=> "single-click"
 ;;=> "single-click"

编辑:

基于Taylor Wood's answer,这里是一个抽象,它为您包装html元素args并覆盖:on-click:on-double-click

代码语言:javascript
复制
(defn ensure-single-double-click 
  [{:keys [on-click on-double-click] :as args}]
  (let [waiting? (atom false)]
    (merge 
     args
     {:on-click (fn [e] 
                  (when (compare-and-set! waiting? false true)
                    (js/setTimeout 
                     (fn [] (when @waiting?
                            (on-click %)
                            (reset! waiting? false)))
                     300)))
      :on-double-click (fn [e] 
                         (reset! waiting? false)
                         (on-double-click %))})))

[:a (ensure-single-double-click
      {:style           {:color "blue"} ;; this works
       :on-click        #(print "single-click")
       :on-double-click #(print "double-click")})
    "test"]
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-08 19:25:53

Taylor Wood's answer很接近,但compare-and-set!并没有保护我不受三次点击(甚至更多的点击!)的影响,因为如果在500 is内发生三次点击,waiting?将在第三次左右再次设置为false,并安排第二次超时。我认为这意味着技术上每一次奇数点击都会有一个新的超时。

幸运的是,click事件附带了一个名为detail的属性,该属性被设置为连续单击的次数。我找到它了here。以下内容应该解决OP的问题,而不允许三次单击:

代码语言:javascript
复制
:on-click
(fn [e]
 ; This prevents the click handler from running
 ; a second, third, or other time.
 (when (-> e .-detail (= 1))
   (reset! waiting? true))
   ; Wait an appropriate time for the double click
   ; to happen...
   (js/setTimeout
     (fn []
       ; If we are still waiting for the double click
       ; to happen, it didn't happen!
       (when @waiting?
         (single-click-fn %)
         (reset! waiting? false)))
     500)))
:on-double-click #(do (reset! waiting? false)
                      (double-click-fn %))

尽管三重点击可能听起来有些异国情调,但它们确实起到了一定的作用:选择一整行文字,所以我不想让用户错过这种能力。

其余部分是对那些有兴趣让文本选择工作的元素的增编,这些元素只需一次点击就可以收听。我是从谷歌来的,想知道该怎么做,所以也许能帮上忙。

我遇到的一个挑战是,我的应用程序要求用户可以执行双击,而不首先释放第二次单击;有点像“一次半点击”。为什么?因为我正在监听span上的单击,用户很可能执行双击来选择一个完整的单词,但接着按下第二次单击并拖动鼠标,以便在原始单词旁边选择其他单词。问题是双击事件处理程序只有在用户释放第二次单击之后才会触发,因此waiting?没有按时设置为false

我使用:on-mouse-down处理程序解决了这个问题:

代码语言:javascript
复制
:on-click
(fn [e]
 ; This prevents the click handler from running
 ; a second, third, or other time.
 (when (-> e .-detail (= 1))
   (reset! waiting? true))
   ; Wait an appropriate time for the double click
   ; to happen...
   (js/setTimeout
     (fn []
       ; If we are still waiting for the double click
       ; to happen, it didn't happen!
       (when @waiting?
         (single-click-fn %)
         (reset! waiting? false)))
     500)))
:on-double-click #(double-click-fn %)
:on-mouse-down #(reset! waiting? false)

请记住,:on-click:on-double-click处理程序只在发布时触发(并且处理程序按鼠标向下、单击、双击的顺序启动),这使:on-mouse-down处理程序有机会将waiting?设置为false,如果用户尚未释放鼠标,则需要将其设置为false,因为他不会触发:on-double-click事件处理程序。

请注意,现在您甚至不需要在双击处理程序中将waiting?设置为false,因为鼠标向下的处理程序在运行双击处理程序时已经完成了该操作。

最后,在我的特定应用程序中,用户可能希望在不触发单击处理程序的情况下选择文本。为了做到这一点,他将点击一段文字,在不释放鼠标的情况下,拖动光标来选择更多的文本。当游标被释放时,不应该触发单击事件。因此,我必须另外跟踪用户是否在松开鼠标(一种“半点击”)之前在任何时候做出选择。在这种情况下,我不得不向组件的状态添加一些东西(一个名为selection-made?的布尔原子和一个名为selection-handler的事件处理程序函数)。这种情况依赖于对选择的检测,而且由于选择是在双击下进行的,因此不需要再检查事件的细节属性来防止三次或更多的单击。

整个解决方案看起来是这样的(但是请记住,这是专门针对文本元素的,因此只是OP要求的一个补充):

代码语言:javascript
复制
(defn component
  []
  (let [waiting? (r/atom false)
        selection-made? (r/atom false)
        selection-handler
        (fn []
          (println "selection-handler running")
          (when (seq (.. js/document getSelection toString))
            (reset! selection-made? true)))]
    (fn []
      [:div
        ; For debugging
        [:pre {} "waiting? " (str @waiting?)]
        [:pre {} "selection-made? " (str @selection-made?)]
        ; Your clickable element
        [:span
          {:on-click
           (fn [e]
            (println "click handler triggered")
            ; Remove the selection handler in any case because
            ; there is a small chance that the selection handler
            ; was triggered without selecting any text (by
            ; holding down the mouse on the text for a little
            ; while without moving it).
            (.removeEventListener js/document "selectionchange" selection-handler)
            (if @selection-made?
              ; If a selection was made, only perform cleanup.
              (reset! selection-made? false)
              ; If no selection was made, treat it as a
              ; simple click for now...
              (do
                (reset! waiting? true)
                ; Wait an appropriate amount of time for the
                ; double click to happen...
                (js/setTimeout
                  (fn []
                    ; If we are still waiting for the double click
                    ; to happen, it didn't happen! The mouse-down
                    ; handler would have set waiting? to false
                    ; by now if it had been clicked a second time.
                    ; (Remember that the mouse down handler runs
                    ; before the click handler since the click handler
                    ; runs only once the mouse is released.
                    (when @waiting?
                      (single-click-fn e)
                      (reset! waiting? false)))
                  500))))
           :on-mouse-down
           (fn [e]
            ; Set this for the click handler in case a double
            ; click is happening.
            (reset! waiting? false)
            ; Only run this if it is a left click, or the event
            ; listener is not removed until a single click on this
            ; segment is performed again, and will listen on
            ; every click everywhere in the window.
            (when (-> e .-button zero?)
              (js/console.log "mouse down handler running")
              (.addEventListener js/document "selectionchange" selection-handler)))
           :on-double-click #(double-click-fn %)}
          some content here]])))
票数 1
EN

Stack Overflow用户

发布于 2018-02-25 02:10:42

有一种方法可以做到:

代码语言:javascript
复制
(defn slow-link [text single-click-fn double-click-fn]
  (let [waiting? (atom false)]
    [:a {:on-click #(when (compare-and-set! waiting? false true)
                      (js/setTimeout (fn [] (when @waiting?
                                              (single-click-fn %)
                                              (reset! waiting? false)))
                                     500))
         :on-double-click #(do (reset! waiting? false)
                               (double-click-fn %))}
     text]))

[slow-link "Test" #(prn "single-click") #(prn "double-click")]

这将启动一个JS定时器,该定时器将在500 JS之后执行给定的函数。该函数检查超时结束时是否仍然是waiting?,如果是,则执行single-click-fn。如果我们不是waiting?,这意味着双击事件已经发生,请将waiting?重置为false,并调用double-click-fn

:on-click处理程序使用compare-and-set只在我们还没有处于waiting?状态时才采取行动,避免了三次/四次单击时的一些活跃行为,等等。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48969496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档