我正在尝试使用 vanilla js 创建一个简单的富文本编辑器,以便了解有关选择对象(
window.getSelection()
)的更多信息,并且正如 js 文档中提到的 mdn 那样,以确保您拥有用户选择的一系列文本rangeCount
属性必须大于零,type
属性是“范围”,并且 isCollapsed
属性等于 false,否则没有选择文本。
这在大多数浏览器中都能正常工作,但在 Chrome 中却并非如此。
即使没有选择任何内容,选择对象也会返回一个范围。
<div id="wysiwyg" contenteditable="true">
<p>
text
</p>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
</div>
<div>
<button type="button" id="click">
click
</button>
</div>
(() => {
const button = document.getElementById("click");
button.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation()
let selection = window.getSelection(),
rangeCount = (selection.rangeCount > 0) ? selection.rangeCount : null,
range = null;
if(rangeCount && selection.type === "Range" && selection.isCollapsed === false ) {
// only MoZilla Firefox allows more than one selection (range could be greater than 1)
if (rangeCount > 1) {
for (let index = 0; index < rangeCount; index++) {
range[index] = selection.getRangeAt(index);
}
}else {
range = selection.getRangeAt(0);
}
}
console.log(range);
});
})();
当没有选择文本时,返回的选择对象必须具有不同的值。
window.getSelection()
方法在浏览器之间可能有点奇怪。如果 Chrome 浏览器为您提供了一个范围,而您认为不应该有一个范围,则可以进一步检查该范围以确定它是有效的文本选择还是只是光标位置。验证这一点的一种方法是检查范围的内容并检查它是否为空。
这是事件监听器的改进版本,它尝试处理这个特定于 Chrome 的怪癖:
button.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation()
let selection = window.getSelection(),
rangeCount = (selection.rangeCount > 0) ? selection.rangeCount : null,
range = null;
if(rangeCount && selection.type === "Range" && selection.isCollapsed === false ) {
// only MoZilla Firefox allows more than one selection (range could be greater than 1)
if (rangeCount > 1) {
for (let index = 0; index < rangeCount; index++) {
let tempRange = selection.getRangeAt(index);
// Check if the range actually contains text for Chrome
if (!isRangeEmpty(tempRange)) {
range[index] = tempRange;
}
}
} else {
let tempRange = selection.getRangeAt(0);
// Check if the range actually contains text for Chrome
if (!isRangeEmpty(tempRange)) {
range = tempRange;
}
}
}
console.log(range);
});
// Helper function to check if a range is empty
function isRangeEmpty(range) {
return range.toString().trim() === "";
}
在上面的代码中,我们添加了一个辅助函数
isRangeEmpty
,它检查范围是否包含任何文本。如果范围为空(即使它在技术上是有效范围),我们可以将其视为没有选择。
这应该有助于规范跨浏览器的行为。但是,请始终记住,随着浏览器更新并改变其行为,特定于浏览器的怪癖可能会成为一个移动目标。在不同浏览器上定期测试您的 Web 应用程序以确保行为一致总是一个好主意。