【问题标题】:How do I prevent Element.focus() change cursor position in contenteditable div?如何防止 Element.focus() 在 contenteditable div 中更改光标位置?
【发布时间】:2020-06-01 19:49:19
【问题描述】:

我不想在任何地方移动光标,但是当我调用函数焦点时,它会将光标移动到开头。我希望将光标保持在原位。我正在使用 Typescript 在 ReactJS 中执行此操作。

const element = document.getElementById('editable-div');
element.focus();   // sets cursor to beginning here
// rest of my code is here

我想调用焦点,因为我需要在 contenteditable div 中附加内容,并且在某些情况下插入内容。但是一旦我执行focus(),它就会将光标移动到错误的位置。我该如何解决这个问题?

【问题讨论】:

  • 当您只打算追加或插入内容时,为什么需要调用focus 方法?你有innerHTML
  • @NafizAhmed 插入可以在 contenteditable div 中的任何位置,具体取决于光标的位置

标签: javascript reactjs typescript


【解决方案1】:

document.createRangeWindow.getSelection 的帮助下,这是可能的

const { useState, useEffect, useRef } = React;

const random = (from, to) => Math.floor(Math.random() * (to - from) + from);
const randomText = () => Array(random(5, 10)).fill(0).map((pr, index) => String.fromCharCode(index + 50)).join('')

const setCaretToTheEnd = (element) => {
  const position = element.textContent.length;
  const [childNode] = element.childNodes;
  const range = document.createRange();
  const selection = window.getSelection();
  range.setStart(childNode, position);
  range.setEnd(childNode, position);
  range.collapse(true);
  selection.removeAllRanges();
  selection.addRange(range);
}

const App = () => {
  const [text, setText] = useState('');
  const inputRef = useRef(null);
  
  useEffect(() => {
    if(inputRef && inputRef.current && text) {
      const element = inputRef.current;
            
      setCaretToTheEnd(element);
      element.focus();
    }
  }, [text]);
  
  useEffect(() => {
    let isUnmounted = false;
    let handle = null;
    
    const changeText = () => {
      setText(randomText());
    
      handle = setTimeout(changeText, 4000);
    }
    
    handle = setTimeout(changeText, 500);
    
    return () => {
      isUnmounted = true;
      clearTimeout(handle);
    }
  }, [])

  const onChange = ({target: {value}}) => setText(value);

  return <div>
    <div ref={inputRef} suppressContentEditableWarning={true} className="contentEditable" onChange={onChange} contentEditable>{text}</div>
  </div>
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
.contentEditable {
  padding: 1rem;
  border: 1px solid black;
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
<div id="root"></div>
<script src="https://unpkg.com/material-ui-lab-umd@4.0.0-alpha.32/material-ui-lab.development.js"></script>
<div id="root"></div>

【讨论】:

  • 嘿,目的并不总是在最后发送插入符号。假设用户返回并认为他也想在中间添加一些东西,所以不应该将插入符号设置到结束位置。
  • 然后你可以扩展函数并将插入符号移动到任何你想要的地方
  • 在调用element.focus() 之前如何找回插入符号的位置?因为只要我调用focus,插入符号就会回到开头,插入符号位置丢失,我不知道将插入符号移动到哪里。
猜你喜欢
  • 2011-04-16
  • 1970-01-01
  • 2011-02-21
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
  • 2015-05-29
  • 2013-04-18
相关资源
最近更新 更多