【问题标题】:Reset content editable caret position重置内容可编辑的插入符号位置
【发布时间】:2020-07-24 02:06:01
【问题描述】:

我目前正在尝试为 Javascript 创建一个语法荧光笔,我目前面临的问题是我发现创建类似这样的东西很常见,它将插入符号位置设置到末尾,而用户键入或编辑内容可编辑的文本。

我在 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

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

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


下面是小提琴链接

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

谢谢。

【问题讨论】:

  • 你宁愿使用类似github.com/codemirror/codemirror的东西
  • 是的,我知道它存在,但这对我来说是一个学习曲线,我需要了解如何做到这一点
  • 好吧,我花了一些时间试图理解为什么它不计算 LF,我看到的是,如果你在第一行的末尾,或者在第二个开始。所以我相信这样做的唯一方法是逐行分割元素。
  • 请你解释一下“逐行分割元素”是什么意思?
  • 默认情况下用户键入时插入符号位置设置为结束,您不需要任何JS代码来设置插入符号位置。默认情况下,它就像任何其他文本字段一样

标签: javascript html caret


【解决方案1】:

问题

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

我可以通过将这一行从 document.getSelection().collapse(e, pos); 更改为 document.getSelection().collapse(e.firstChild, pos); 来修复 setPos 函数

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

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

解决方案

我建议创建一个&lt;span id="caret-position"&gt;&lt;/span&gt; 元素来跟踪插入符号的位置。

它会像这样工作:

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 fiddle:https://jsfiddle.net/Vehmloewff/0j8hzevm/132/

已知问题:点击两次Enter 后,它会丢失插入符号的位置。我不太清楚为什么会这样。

【讨论】:

  • 感谢您,但我看到的小提琴仍然存在问题,但我非常感谢您的尝试
  • @WhiteHox 很难做你想做的事。您可能必须镜像一个文本区域才能获得您正在寻找的结果。
猜你喜欢
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-10
  • 1970-01-01
  • 2017-04-17
相关资源
最近更新 更多