【问题标题】:Why does select() not work on Safari with ReactJS?为什么 select() 在带有 ReactJS 的 Safari 上不起作用?
【发布时间】:2019-06-11 06:22:19
【问题描述】:

每当我单击/点击/聚焦该字段时,我都希望获得一个 TextField 来选择当前在该字段中的整个文本。以下代码适用于 Chrome (71.0.3578.98),但不适用于 Safari (12.0.2)。任何想法为什么?

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  return (
    <>
      <h1>Test Focus React</h1>
      <input
        type="text"
        defaultValue="test"
        onFocus={event => {
          event.target.select();
        }}
      />
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

然而这个没有任何 React 的静态 HTML 文件在 Safari 上运行良好。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Test Focus JS</title>
  </head>
  <body>
    <h1>Test Focus JS</h1>
    <input type="text" value="test" onClick="this.select();" />
  </body>
</html>

谁能帮我看看如何使用 React 让选择在 Safari 上工作?

【问题讨论】:

    标签: reactjs safari


    【解决方案1】:

    当与 DOM 交互之类的事情失败时,通常与事件如何在不同的上下文(react 与 onclick)中同步/异步触发有关,甚至与浏览器(Safari 有时会进行奇怪的优化)有关。

    我猜它只会通过使其异步来工作,例如:

    import React from "react";
    import ReactDOM from "react-dom";
    
    import "./styles.css";
    
    function App() {
      return (
        <>
          <h1>Test Focus React</h1>
          <input
            type="text"
            defaultValue="test"
            onFocus={event => {
                  // event properties must be copied to use async
                  const target = event.target;
                  setTimeout(() => target.select(), 0);
            }}
          />
        </>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    【讨论】:

    • 这在桌面 Safari 上成功了,但在移动 Safari 上似乎仍然失败。 ref 方法在 Mobile Safari 上也失败了。但是,如果我将 select 替换为 setSelectionRange(0, 9999),则它适用于 Mobile Safari、Safari 和 Chrome。
    【解决方案2】:

    这是众所周知的问题,您基本上可以使用set timeout 解决这个问题

    onFocus={event => {
      setTimeout(event.target.select.bind(event.target), 20);
    }}
    

    这里正在工作example。我在 safari 上测试过,没有任何问题。

    【讨论】:

    • 你确定这是一个错误吗? React 提供了一种使用 refs 来做这件事的方法。
    • 对不起,我的意思是问题。我修正了我的答案。
    【解决方案3】:

    我认为您想使用 React ref 来存储对实际 input DOM 元素的引用,以便您可以从 onClick 方法对其调用 select。

    查看文档,他们有一个很好的示例,您可以稍作修改以满足您的需求:https://reactjs.org/docs/refs-and-the-dom.html

    我认为这应该可行:

    import React from "react";
    import ReactDOM from "react-dom";
    
    import "./styles.css";
    
    class CustomTextInput extends React.Component {
      constructor(props) {
        super(props);
    
        this.textInput = React.createRef();
        this.selectTextInput = this.selectTextInput.bind(this);
      }
    
      selectTextInput() {
        this.textInput.current.select();
      }
    
      render() {
        return (
          <div>
            <input 
              type="text" 
              defaultValue="pizza" 
              ref={this.textInput} 
              onClick={this.selectTextInput}
            />
          </div>
        );
      }
    }
    
    function App() {
      return (
        <CustomTextInput />
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    【讨论】:

    • 谢谢,这似乎可行(尽管移动 Safari 可能需要 setSelectionRange(0,9999) 而不是 select())。但是,这对于我的实际用例来说有点太复杂了。当表单变得更复杂并且 Typescript 进入图片时,使用 refs 会变得很松散。
    • 我想随着表单复杂性的增加,使用异步 setTimeout 方法也会变得松鼠。 ;-)
    • 我发现在另一种方法中更容易的是,许多元素可以共享同一个处理程序,而无需定义 refs。我可以使用event.currentTarget 到达正确的目标,而完全不必担心“谁”联系了处理程序。这感觉更简单。当然,我可能会在此过程中遇到不利因素,并感谢您使用ref 的课程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 2017-06-11
    • 2020-05-25
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2019-04-11
    相关资源
    最近更新 更多