首页 > 解决方案 > `textNode.splitText(pos)` 在 Safari 中弄乱了插入符号的位置,将其移动到新节点之前。漏洞?

问题描述

在 Safari 中使用拆分文本节点(在键入时).splitText()时,插入符号会在新创建的节点之前移动 - 在 Chrome 和 Firefox 中,它按预期保持其在行尾的位置。

我想知道,我是否遇到过错误,什么是干净的解决方法?

function wrapWorld({target}) {
  const node = target.childNodes[0];
  const pos = node.nodeValue.indexOf('world');
  console.log(pos);
  
  if (pos > 0) {
    //watch the caret in Safari jump before "world" when split :(
    const newNode = node.splitText(pos);
  }
}
#editor {
  width: 300px;
  height: 130px;
  border: 1px solid #ccc;
}
<p>Type "hello world" in Safari, watch the caret jump before "world" when it gets split</p>

<div id="editor" 
     contenteditable="true"
     oninput="wrapWorld(event)">
</div>

标签: javascripttextsafarinodescaret

解决方案


我不能确定这是否真的是一个错误,我没有在规范中进行广泛的搜索以了解这里应该发生什么(内容可编辑通常是规范不足的......),但这两种行为听起来对我来说很合乎逻辑,就像我希望光标在刚刚删除内容时返回一样。

现在,您实际上可以强制 Chrome 和 Firefox 的行为,无论如何这可能是一个好主意。

为此,请使用Selection API了解光标当前的位置,然后在进行拆分后,将其设置为新位置,您可以使用拆分索引进行计算。

function wrapWorld( { target } ) {
  const sel = getSelection(); // get current selection
  const range = sel.getRangeAt( 0 ); // extract active Range
  const node = range.endContainer; // we should be collapsed, so startContainer === endContainer
  const cursor_pos = range.endOffset; // the position of our cursor in the whole node
  const txt_pos = node.nodeValue.indexOf( 'world' );

  if ( txt_pos > -1 ) {
    const new_node = node.splitText( txt_pos );
    const new_pos = cursor_pos - txt_pos;
    if( new_pos > -1 ) {
      range.setStart( new_node, new_pos ); // update our range
      sel.removeAllRanges();
      sel.addRange( range ); // update the Selection
    }
  }
}
#editor {
  width: 300px;
  height: 130px;
  border: 1px solid #ccc;
}
<p>Type "hello world" in Safari, watch the caret stay where it belongs</p>

<div id="editor" 
     contenteditable="true"
     oninput="wrapWorld(event)">
</div>


推荐阅读