如何将插入符号定位在其中还没有文本的 span 元素内?
How do I position the caret inside a span element that has no text inside of it yet?
按照 SO post,我可以将插入符号放在 span
元素内,该元素位于 div contenteditable="true"
.
内
我可以通过它的 id
来定位我想要的 span
,同时还可以决定插入符号应该放在哪个字符之后。
但是我怎样才能将插入符放在没有文本的范围内呢?
按原样简单地使用函数,得到这个错误:TypeError: Range.setStart: Argument 1 is not an object.
另外,出于某种原因,当 span
有内容时,它在 Firefox 中工作正常。但不在 Chrome 中,其中插入符号位于 span
之外。有什么办法也能解决这个问题吗?
我愿意 jQuery,如果它能让事情变得更容易的话。
这是我的代码:
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>
zero-width space 有一个很好的技巧,你可以考虑(看看下面的代码)和 CSS 属性 white-space: pre
允许space聚焦时“可见”。
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] 未定义,这将 return 节点:
range.setStart(node.childNodes[0] || node, 0);
第二种情况出现问题是因为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>
按照 span
元素内,该元素位于 div contenteditable="true"
.
我可以通过它的 id
来定位我想要的 span
,同时还可以决定插入符号应该放在哪个字符之后。
但是我怎样才能将插入符放在没有文本的范围内呢?
按原样简单地使用函数,得到这个错误:TypeError: Range.setStart: Argument 1 is not an object.
另外,出于某种原因,当 span
有内容时,它在 Firefox 中工作正常。但不在 Chrome 中,其中插入符号位于 span
之外。有什么办法也能解决这个问题吗?
我愿意 jQuery,如果它能让事情变得更容易的话。
这是我的代码:
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>
zero-width space 有一个很好的技巧,你可以考虑(看看下面的代码)和 CSS 属性 white-space: pre
允许space聚焦时“可见”。
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] 未定义,这将 return 节点:
range.setStart(node.childNodes[0] || node, 0);
第二种情况出现问题是因为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>