【问题标题】:React webkit controlled-component textarea loses focus on keystroke renderReact webkit 受控组件文本区域失去了对击键渲染的关注
【发布时间】:2020-08-05 18:48:15
【问题描述】:

我正在使用 Antd Mobile 组件库编写一个带有客户端渲染的 React 非原生 webapp。

"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-redux-router": "0.0.14",
"react-router-dom": "^5.2.0",
"antd": "^4.4.0",
"antd-mobile": "^2.3.3",

我有一个带有 2 个文本区域作为受控组件的小表单。当用户在桌面浏览器(safari、firefox、chrome 等)上编辑文本时,它可以正常工作而不会失去焦点。但是在 webkit 上,这些字段在模型更新 render() 期间失去焦点。我正在使用静态字符串键并已实现 ref 挂钩来重置焦点和光标位置。每次击键后,虚拟键盘消失,光标从文本区域中移除。该模块被编写为“纯”功能组件(而不是类)。

任何想法为什么 webkit 会遇到这个问题?

下面是感兴趣的部分代码:

   const useFocus = () => {
      const htmlElRef = useRef(null);
      const setFocus = () => {
         htmlElRef.current && htmlElRef.current.focus();
      };
      return [htmlElRef, setFocus];
   };

   const [focusRef, setFocusRef] = useFocus();

[snip]
              key="myfieldkey"
               name="myfield"
               title="MyLabel:"
               ref={focusRef}
               onChange={(value) => {
                  let cursorStart =
                     focusRef.current.textareaRef.selectionStart;
                  onFieldChange(value /* update model */ );
                  /* timeout gives reducer time to update model */
                  setTimeout(() => {
                     setFocusRef();
                     focusRef.current.textareaRef.setSelectionRange(
                        cursorStart,
                        cursorStart
                     );
                  }, 40);
               }}

【问题讨论】:

    标签: reactjs webkit focus textarea render


    【解决方案1】:

    我找到了解决方法,但如果您发现自己有真正的答案,我将非常感谢任何真正的答案。它相当复杂,但似乎适用于所有平台:

    1. 为每个文本区域创建一个局部状态变量,用于存储当前光标位置。例如。
    const [nameFieldCursorPos, setNameFieldCursorPos] = useState(undefined);
    
    1. 修改我的useFocus() 函数如下,包括从输入参数设置光标位置。例如。
        const useFocus = () => {
            const htmlElRef = useRef(null);
            const setFocus = (cursorPos) => {
               htmlElRef.current && htmlElRef.current.focus();
               if (cursorPos) {
                  htmlElRef.current.textareaRef.setSelectionRange(
                     cursorPos,
                     cursorPos
                  );
               }
            };
            return [htmlElRef, setFocus];
         };
    
    1. 对于每个 textarea 字段,创建更多状态以获取/设置焦点。例如。
        const [nameFocusRef, setNameFocusRef] = useFocus();
    
    1. 对于每个 textarea 字段,创建一个 useLayoutEffects() 处理程序以在渲染后重置焦点/光标位置。例如:
        useLayoutEffect(() => {
           if (nameFieldCursorPos) {
              setNameFocusRef(nameFieldCursorPos);
           }
        }, [nameFieldCursorPos, setNameFocusRef]);
    
    1. 对于每个 textarea 字段,在您的 on change 处理程序中,将任何其他光标位置设置为 undefined,保存您自己的光标位置并设置焦点,然后调用您真正的更改处理程序来更新您的值状态(如在 redux 或哪里):
        onChange={(value) => {
           // wipe any other field's saved cursor pos
           setSummaryFieldCursorPos(undefined);
           setTextFieldCursorPos(undefined);
           setCategoryFieldCursorPos(undefined);    
    
           // save off my fields cursor pos / focus
           setNameFieldCursorPos(
                nameFocusRef.current.textareaRef.selectionStart
           );    
    
           // update value state
           onNameChange(value);
        }}
    

    【讨论】:

      猜你喜欢
      • 2014-04-06
      • 2017-12-29
      • 2018-07-05
      • 2017-04-12
      • 1970-01-01
      • 2020-03-05
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多