【问题标题】:insert a span in a contenteditable, and then user can not continue input after and out the span that just be insert在 contenteditable 中插入一个 span,然后用户无法在刚刚插入的 span 之后继续输入
【发布时间】:2020-04-17 15:00:37
【问题描述】:
  • 代码目标:当用户按下空格时,自动输入一个span,然后用户可以继续输入,
  • 当我在 devtools 中跟踪它们时,range.setEnd(lasttextnode, 0);并且 range.collapse() 以正确的方式运行,
  • 但是键盘输入不对,我在文本上设置了插入符号,想在跨度之后插入字符,但输入出现在刚刚插入的前一个跨度中。

这是我的代码:

editor.onkeydown = editinput;
var sel = window.getSelection();

function editinput(e) {
  var range = sel.getRangeAt(0);

  if (e.isComposing || e.keyCode === 229) { //imk
    return;
  }
  if (e.keyCode == 32) { //space

    var tnode = range.commonAncestorContainer;
    var start = range.startOffset;
    var text = tnode.textContent;

    var span = document.createElement('span');
    span.innerHTML = '------span------';

    var firsttextnode = document.createTextNode(text.substring(0, start));
    var lasttextnode = document.createTextNode(text.substring(start));
    var fragment = new DocumentFragment();
    fragment.append(firsttextnode, span, lasttextnode);
    tnode.replaceWith(fragment);
    range.setEnd(lasttextnode, 0); // here is problem,
    range.collapse();

    e.stopPropagation(); //bubble
    e.preventDefault(); //default.
  }
}
[contenteditable=true] {
  display: inline-block;
  white-space: pre-wrap;
  width: 400px;
  height: 100%;   
}

div, textarea,   span {
  border: 1px solid rgba(122, 206, 143, 0.966);
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
<div id="editor" contenteditable="true" class="Weave" tabIndex="1">
  samelinesamelinesamelinesamelinesamelinesamelinesame
  <span>deerge span</span>oaeueouaoeu <span>disange span</span>
</div>

您可以看到:键盘输入将在刚刚插入的范围内。

但如果我将range.setEnd(lasttextnode, 0); 更改为range.setEnd(lasttextnode, 1),它将正常运行;

我尝试了很多方法:

  1. range.collapse();
  2. range.setStart(lasttextnode,0)
  3. sel.removeAllRanges();
  4. sel.collapse(lasttextnode,0)
  5. range.setStartBefore(lasttextnode);
  6. range.setStartAfter(span);

所有这些都不起作用。只需在 lasttextnode 之前插入一个空格就可以部分解决问题,但这不是我的目标,我想在 span 之后输入一些内容。

【问题讨论】:

  • 您曾说过(在标题中)“不能超出跨度”,然后您说的是“您可以看到:键盘输入将在刚刚插入的跨度中”。现在,我问:“你想要插入符号在跨度内,还是你想要它在跨度之后?”。另外,您说过,“然后用户可以继续输入”。那么,问题是,用户应该从哪里继续输入?
  • 谢谢@RahulVerma,我改了标题,我明白你的意思了吗?
  • (在标题中)我认为您的意思是“可以继续输入”。 另外,我问过你,“用户应该从哪里继续输入输入?(在范围内在范围外)”
  • 我想在跨度之外,但不能。

标签: javascript html range selection keyboard-input


【解决方案1】:

您可以尝试在跨度和最后一个文本节点之间插入一个空字符(例如\u200B)。然后,当您将光标移到最后一个文本节点之前,它位于跨度标记之外。但请记住在将结果插入数据库之前从结果中删除空字符。

editor.onkeydown = editinput;
var sel = window.getSelection();

function editinput(e) {
  var range = sel.getRangeAt(0);

  if (e.isComposing || e.keyCode === 229) { //imk
    return;
  }
  if (e.keyCode == 32) { //space

    var tnode = range.commonAncestorContainer;
    var start = range.startOffset;
    var text = tnode.textContent;

    var span = document.createElement('span');
    span.innerHTML = '------span------';
    var emptyNode = document.createTextNode('\u200B');

    var firsttextnode = document.createTextNode(text.substring(0, start));
    var lasttextnode = document.createTextNode(text.substring(start));
    var fragment = new DocumentFragment();
    fragment.append(firsttextnode, span, emptyNode, lasttextnode);
    tnode.replaceWith(fragment);
    range.setEnd(lasttextnode, 0); // here is problem,
    range.collapse();

    e.stopPropagation(); //bubble
    e.preventDefault(); //default.
  }
}
[contenteditable=true] {
  display: inline-block;
  white-space: pre-wrap;
  width: 400px;
  height: 100%;   
}

div, textarea,   span {
  border: 1px solid rgba(122, 206, 143, 0.966);
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
<div id="editor" contenteditable="true" class="Weave" tabIndex="1">
  samelinesamelinesamelinesamelinesamelinesamelinesame
  <span>deerge span</span>oaeueouaoeu <span>disange span</span>
</div>

【讨论】:

  • 这看起来是个不错的解决方案,但是下次我获取 doc 表单数据库并将其显示在 contenteditable 上时,我必须在正确的位置插入 \u220b 吗?我明白了吗?
  • 不,没有必要。 \u220b 只是编辑器的占位符。仅用于编辑时移动光标。
  • 不过就算忘记清理\u220b标签也没关系。唯一的缺点是输出 HTML 中有一些不可见的字符。
  • 好的,我去试试,我担心什么时候拿回来,没有\u220b,然后span之后就不能输入了,如果是真的,我会保留\u220b 总是。再次感谢您,无论如何,您已经解决了我的问题,谢谢。
【解决方案2】:

您可以尝试添加另一个节点,只有一个空格,然后在该节点上设置结束。

var firsttextnode = document.createTextNode(text.substring(0, start));
var lasttextnode = document.createTextNode(text.substring(start));
var emptyNode = document.createTextNode(' ');
var fragment = new DocumentFragment();
fragment.append(firsttextnode, span, lasttextnode, emptyNode);
tnode.replaceWith(fragment);
range.setEnd(emptyNode, 1);
range.collapse();

https://jsfiddle.net/63s1tgyw/

它将聚焦在跨度之外。这是你想要达到的目标吗?

【讨论】:

  • 只需输入一个空格,lasttextnode 也可以解决它,但这不是我想要找到的。我想在跨度之后输入一些接近的东西,而不是插入一个无用的空间。无论如何感谢您的回答,尤其是第一个答案。
猜你喜欢
  • 2018-10-28
  • 1970-01-01
  • 2019-09-26
  • 2015-04-21
  • 2014-11-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2010-11-24
相关资源
最近更新 更多