重置内容可编辑的插入符位置

时间:2020-04-11 10:26:00

标签: javascript html caret

我目前正在尝试为 Javascript 创建语法突出显示工具,并且目前我遇到的问题是创建这样的东西(将插入符号的位置设置为末尾)很常见。用户键入或编辑contentEditable文本。

我在SO上进行了研究,发现this和许多其他解决方案,但均无效果。它获得了插入符号的位置,但从未重置它,因此我正在尝试找到解决此问题的方法。

下面是我想出的代码。

html

<div id="editor" contentEditable="true" onkeyup="resetPosition(this)"></div>

<input type="text" onkeyup="resetPosition(this)" />

js

function getPos(e) {
    // for contentedit field
  if (e.isContentEditable) {
    e.focus()
    let _range = document.getSelection().getRangeAt(0)
    let range = _range.cloneRange()
    range.selectNodeContents(e)
    range.setEnd(_range.endContainer, _range.endOffset)

    return range.toString().length;
  }
  // for texterea/input element
  return e.target.selectionStart
}


function setPos(pos, e) {
  // for contentedit field
  if (e.isContentEditable) {
      e.focus()
      document.getSelection().collapse(e, pos);
      return
  }
  e.setSelectionRange(pos, pos)
}

function resetPosition(e) {
  if(e.isContentEditable) {
  let currentPosition = getPos(e);
  e.innerHTML=e.innerHTML.replace(/[0-9]/g, "a");
  setPos(currentPosition, e);

  return;
}

  e.value = e.value.replace(/[0-9]/g, "a");
  setPos(currentPosition, e);

}     

这对于文本输入有效,但对于contentEditable divs则无效。

当我输入类似function的内容时,我得到otincfun

更新:我可以通过将此行从setPos更改为document.getSelection().collapse(e, pos);来修复document.getSelection().collapse(e.firstChild, pos);函数,但是出现了一个新的错误。

当我按Enter键时,插入符号返回到第一行和第一个字符。请问我该如何解决?


下面是小提琴链接

https://jsfiddle.net/oketega/bfeh9nm5/35/

谢谢。

1 个答案:

答案 0 :(得分:3)

问题

document.getSelection().collapse(element, index)将光标折叠到index所指向的子节点,而不是字符索引。

通过将这一行从setPos更改为document.getSelection().collapse(e, pos);,我能够修复document.getSelection().collapse(e.firstChild, pos);功能

如果仅替换字符,这将起作用,但是,如果要创建语法荧光笔,则需要将字符放在span元素中以设置样式。 e.firstChild只会将位置设置为e的第一个孩子内的索引,不包括后一个span

要考虑的另一件事是,您可能需要自动完成某些字符。在操作文本之前,插入符号的位置可能与在操作之后的插入符号位置不同。

解决方案

我建议创建一个<span id="caret-position"></span>元素以跟踪插入符号的位置。

它会像这样工作:

function textChanged(element) {
    // 1
    const text = setCursorMarker(element.innerText, element);

    // 2
    const html = manipulate(text);
    element.innerHTML = html;

    // 3
    const index = findCursorIndex(element);
    document.getSelection().collapse(element, index)
}

  1. 每次用户键入时,您都可以获取当前的插入符号位置并在其中的#caret-position元素中滑动。
  2. 用突出显示的语法覆盖现有的html
  3. 找出#caret-position在哪里,然后将插入号放在那里。

注意:当用户键入内容可编辑元素时,建议的监听方式是使用oninput监听器,而不是onkeyup。按住一个键可以插入许多字符。

示例

这里有一个有效的js小提琴:https://jsfiddle.net/Vehmloewff/0j8hzevm/132/

已知问题:两次按下Enter之后,它会丢失对插入符号应该位于的位置的跟踪。我不太确定为什么要这么做。