【发布时间】:2016-05-11 06:27:22
【问题描述】:
(我对 OM 和 React 有点陌生,所以如果这被记录在我还没有看到的某个地方,我深表歉意。)
我正在尝试制作一个文本框,在编辑过程中验证和格式化其输入,类似于autoNumeric JS 库。
我的应用程序用于验证美元货币(例如 $1,234.56 形式的字符串)。具体来说,文本框应防止用户在文本框中输入无效字符(如字母),并应即时格式化其内容以包括美元符号 ($) 和标记千位的逗号。该组件应防止删除这些格式字符。 JS toLocaleString 函数已经很好地处理了格式设置,但是我在 UI 和输入后光标的位置出现问题。
我找到了一个相关的react github issue,它描述了如何防止光标在应用状态更新后跳来跳去。捕获该线程的解决方案是a JS Bin,但它是使用 React 用 javascript 编写的。
我正在尝试使用 ClojureScript 和 Om 实现一个版本,但遇到了麻烦。如果我只使用组件本地状态而不使用全局应用程序状态来实现组件,那么光标会执行预期的行为并且不会跳转(类似于 autoNumeric 库)。最终我想将价值传播到全球应用程序状态。但是,当我让组件更新全局应用程序状态时,每次更改输入字段后光标都会跳转。
我尝试了许多变体,包括不使用本地状态(仅使用全局应用状态)以及混合使用全局和本地。每当我包含全局应用程序状态时,光标都会跳转。
这是我当前的实现,它还没有更新全局应用状态,但没有跳跃光标。 (注意,我用的是om-tools,所以语法可能和vanilla om有点不同。)
(defn raw-number [s]
(let [s (if (empty? s "0" (str s)))]
(js/parseFloat (str/replace s #"[^-0-9.]" ""))))
(defn format-currency [s]
(.toLocaleString (raw-number s) "en-US" #js {:style "currency" :currency "USD"}))
(defcomponentk validated-input
"Component that prevents the cursor from jumping after updates."
[data owner opts]
(will-receive-props [_ new-state]
(when-let [dom-node (om/get-node owner "validated-input")]
(let [old-length (-> dom-node .-value count)
old-idx (.-selectionStart dom-node)
_ (set! (.-value dom-node) new-state)
new-len (count new-state)
new-idx (max 0 (-> new-len (- old-length) (+ old-idx)))]
(om/update! data :cursor-pos new-idx))))
(did-update [_ _ prev-state]
(let [new-idx (:cursor-pos data)
dom-node (om/get-node owner "validated-input")]
(set! (.-selectionStart dom-node) new-idx)
(set! (.-selectionEnd dom-node) new-idx)))
(render [_]
(dom/input
(merge
opts
{:type "text"
:ref "validated-input"}))))
(defcomponentk formatted-input
"Formats the text using the provided formatter before rendering it."
[data owner [:opts formatter :as opts]]
(init-state [_]
{:text (formatter "")})
(render [_]
(let [text (om/get-state owner :text)]
(validated-input
text ;; << I recognize this to be shady, passing local state down. but it works to prevent the cursor jumping.
{:opts
(merge
opts
{:value text
:on-change (fn [e]
(let [new-val (formatter (str (.. e -target -value)))]
(om/set-state! owner :text new-val)))})}))))
【问题讨论】:
-
您必须使用带有受控输入的本地状态。为什么不对全局状态只写(不读)?
标签: validation reactjs clojurescript om