选择所有跨文本时如何获取 <span> 元素?
How to get <span> element when all spanned text selected?
在内容可编辑的 div 中,我想用 <span>
包围 selected 文本,或者当我 select 时修改现有的 <span>
] 其中的所有文字。第一个我可以,第二个不行
在第二种情况下,如果我有 A<span>B</span>C
和 select B,selection 将 anchorNode
显示为 A
,focusNode
为 C
,以及 toString()
returns B
。父节点是封闭的段落,而不是 <span>
。我找不到任何方法来区分 A<span>B</span>C
和 ABC
中的 selecting B
,因为我找不到任何方法来发现 [=12] 的存在=] 在第一种情况下包围 B
的元素。肯定有办法做到这一点,对吧?谁能告诉我怎么做?
代码如下:
var sel = window.getSelection();
var range = sel.getRangeAt(0);
var selected = range.compareBoundaryPoints(range.START_TO_END, range);
if (selected > 0) { // some text is selected
var el = range.commonAncestorContainer;
//
// would expect to find el == <span> if selection is B
// in <p>A<span>B</span>C<p>, but find <p> instead!
//
//... code to surround selection with new span or to process
// existing span... but there is never an existing span!
}
Range.commonAncestorContainer 有一个 属性 叫做 parentElement。它是所选文本的父级。
在代码片段中,伦敦和巴黎都用 span 元素包裹。
const text = "<p>Hello from <span>London</span> and <span>Paris</span></p>"
const parser = new DOMParser();
const html = parser.parseFromString(text, "text/html").body.innerHTML
const editor = document.querySelector('div[contenteditable]')
editor.innerHTML = html
function getParent() {
var selection = window.getSelection();
if (selection.rangeCount) {
const range = selection.getRangeAt(0);
const parent = range.commonAncestorContainer.parentElement;
document.querySelector("#result").innerText = parent instanceof HTMLSpanElement
if (parent instanceof HTMLSpanElement) {
console.log(parent)
}
}
}
document.querySelector("button").onclick = getParent;
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container py-5">
<div class="row align-items-center">
<div class="col">
<div class="w-100 p-5 border" contenteditable>
</div>
</div>
<div class="col">
<button class="btn btn-primary">Get Text</button>
</div>
</div>
<div class="row align-items-center">
<div class="col">
<p>Is Is parent instanceof HTMLSpanElement? <span id="result"></span> </p>
</div>
</div>
</div>
对于上述问题,我想出了一个相当糟糕的解决方法。为了测试选择是否是整个 <span>
元素,我克隆了范围,当它是整个范围时,它包含前后为空字符串的范围。所以我要做的是删除其中任何一个,并检查我剩下的是否是单个 span 元素。如果是这种情况,我将在原始范围开始后取下一个元素,即 <span>
:
var el = range.commonAncestorContainer;
var copy = range.cloneContents();
while (copy.childNodes.length > 1 && copy.firstChild.nodeValue === "") {
copy.removeChild(copy.firstChild);
}
while (copy.childNodes.length > 1 && copy.lastChild.nodeValue === "") {
copy.removeChild(copy.lastChild);
}
if (copy.childNodes.length == 1 && copy.childNodes[0] instanceof HTMLSpanElement) {
el = range.startContainer.nextSibling;
}
这可行,但不是很吸引人。如果有人有更好的解决方案,我会很高兴。
在内容可编辑的 div 中,我想用 <span>
包围 selected 文本,或者当我 select 时修改现有的 <span>
] 其中的所有文字。第一个我可以,第二个不行
在第二种情况下,如果我有 A<span>B</span>C
和 select B,selection 将 anchorNode
显示为 A
,focusNode
为 C
,以及 toString()
returns B
。父节点是封闭的段落,而不是 <span>
。我找不到任何方法来区分 A<span>B</span>C
和 ABC
中的 selecting B
,因为我找不到任何方法来发现 [=12] 的存在=] 在第一种情况下包围 B
的元素。肯定有办法做到这一点,对吧?谁能告诉我怎么做?
代码如下:
var sel = window.getSelection();
var range = sel.getRangeAt(0);
var selected = range.compareBoundaryPoints(range.START_TO_END, range);
if (selected > 0) { // some text is selected
var el = range.commonAncestorContainer;
//
// would expect to find el == <span> if selection is B
// in <p>A<span>B</span>C<p>, but find <p> instead!
//
//... code to surround selection with new span or to process
// existing span... but there is never an existing span!
}
Range.commonAncestorContainer 有一个 属性 叫做 parentElement。它是所选文本的父级。
在代码片段中,伦敦和巴黎都用 span 元素包裹。
const text = "<p>Hello from <span>London</span> and <span>Paris</span></p>"
const parser = new DOMParser();
const html = parser.parseFromString(text, "text/html").body.innerHTML
const editor = document.querySelector('div[contenteditable]')
editor.innerHTML = html
function getParent() {
var selection = window.getSelection();
if (selection.rangeCount) {
const range = selection.getRangeAt(0);
const parent = range.commonAncestorContainer.parentElement;
document.querySelector("#result").innerText = parent instanceof HTMLSpanElement
if (parent instanceof HTMLSpanElement) {
console.log(parent)
}
}
}
document.querySelector("button").onclick = getParent;
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container py-5">
<div class="row align-items-center">
<div class="col">
<div class="w-100 p-5 border" contenteditable>
</div>
</div>
<div class="col">
<button class="btn btn-primary">Get Text</button>
</div>
</div>
<div class="row align-items-center">
<div class="col">
<p>Is Is parent instanceof HTMLSpanElement? <span id="result"></span> </p>
</div>
</div>
</div>
对于上述问题,我想出了一个相当糟糕的解决方法。为了测试选择是否是整个 <span>
元素,我克隆了范围,当它是整个范围时,它包含前后为空字符串的范围。所以我要做的是删除其中任何一个,并检查我剩下的是否是单个 span 元素。如果是这种情况,我将在原始范围开始后取下一个元素,即 <span>
:
var el = range.commonAncestorContainer;
var copy = range.cloneContents();
while (copy.childNodes.length > 1 && copy.firstChild.nodeValue === "") {
copy.removeChild(copy.firstChild);
}
while (copy.childNodes.length > 1 && copy.lastChild.nodeValue === "") {
copy.removeChild(copy.lastChild);
}
if (copy.childNodes.length == 1 && copy.childNodes[0] instanceof HTMLSpanElement) {
el = range.startContainer.nextSibling;
}
这可行,但不是很吸引人。如果有人有更好的解决方案,我会很高兴。