如何将插入符号放置在尚无文本的span元素内?

问题描述

this之后,我能够将插入符号放置在span内的div contenteditable="true"元素内。

我可以通过其span来确定想要的id的目标,同时还可以决定插入符号应放在哪个字符之后。

但是如何将插入符号放在没有文本的跨度内?

仅按原样使用该功能,就会收到此错误TypeError: Range.setStart: Argument 1 is not an object.

由于某种原因,当span包含内容时,它在Firefox中也可以正常工作。但不是在插入符号位于span外部的Chrome中。还有办法解决这个问题吗?

如果让事情变得更容易,我愿意使用jQuery。

这是我的代码

JSFiddle

function setCaret(x,y) {
   var element = document.getElementById(x);
   var range = document.createrange();  
   var node;   
   node = document.getElementById(y);  
   range.setStart(node.childNodes[0],0);
   var sel = window.getSelection();
   range.collapse(true);
   sel.removeAllRanges();
   sel.addRange(range);
   element.focus();    
}
body {
  font-family: sans-serif;
}

input {
  margin-bottom: 5px;
  padding: 3px;
}

input:last-of-type {
  margin-top: 30px;
}

div {
  width: 300px;
  padding: 5px;
  border: solid 1px #000;
}

span {
  font-weight: bold;
}
<input type="button" value="place caret" onclick="setCaret('editableDiv1','span1');">
<div id="editableDiv1" contenteditable="true" spellcheck="false">This one <span id="span1">is</span> working.</div>

<input type="button" value="place caret" onclick="setCaret('editableDiv2','span2');">
<div id="editableDiv2" contenteditable="true" spellcheck="false">This one <span id="span2"></span> is not.</div>

解决方法

有一个不错的技巧,您可以考虑零宽度的空间(请看下面的代码)和CSS属性white-space: pre,该属性允许在聚焦时使空间“可见”。

function makeTextNode() {
    return document.createTextNode('​') // <-- there a zero-width space between quotes
}

function placeCaretInSpan() {
  const range = document.createRange()
  const editable = document.getElementById("editable")
  const span = editable.querySelector("span")
  if (span.childNodes.length === 0) {
    span.appendChild(makeTextNode()) // <-- you have to have something in span in order to place caret inside
  }
  range.setStart(span.childNodes[0],1) // <-- offset by 1 to be inside SPAN element and not before it
  let selection = window.getSelection()
  range.collapse(true)
  selection.removeAllRanges()
  selection.addRange(range)
  editable.focus()
}
span {
    font-weight: bold;
    background: yellow;
}
#editable:focus {
    white-space: pre;
}
<div contenteditable="true" id="editable">This should be <span></span> editable.</div>
<button onclick="placeCaretInSpan()">place caret</button>

,

尝试使用OR运算符,如果未定义node.childNodes [0],它将返回节点:

@nestjs/graphql
,

在第二种情况下会出现问题,因为span2没有内容,并且node.childNodes[0]变成了undefined。下面的代码段中使用了一个小的解决方法。您的代码中唯一更改的行是:

range.setStart(node.childNodes[0],0);

并成为

range.setStart((typeof node.childNodes[0] !== 'undefined' ? node.childNodes[0] : node),0);

您可以在下面查看结果。

function setCaret(x,y) {
   let element = document.getElementById(x);   
   let range = document.createRange();  
   let node = document.getElementById(y);  
   range.setStart((typeof node.childNodes[0] !== 'undefined' ? node.childNodes[0] : node),0);
   let sel = window.getSelection();
   range.collapse(true);
   sel.removeAllRanges();
   sel.addRange(range);
   element.focus();    
}
body {
  padding: 10px;
  font-family: sans-serif;
}

input {
  margin-bottom: 10px;
  padding: 5px;
}

input:last-of-type {
  margin-top: 50px;
}

div {
  width: 300px;
  padding: 5px;
  border: solid 1px #000;
}

span {
  font-weight: bold;
}
<input type="button" value="place caret" onclick="setCaret('editableDiv1','span1');">
<div id="editableDiv1" contenteditable="true" spellcheck="false">This one <span id="span1">is</span> working.</div>

<input type="button" value="place caret" onclick="setCaret('editableDiv2','span2');">
<div id="editableDiv2" contenteditable="true" spellcheck="false">This one <span id="span2"></span> is working also.</div>