Range
对象并document.execCommand
允许很容易地操纵选择。您的情况的主要问题是以文本格式保存范围对象。
基本上,您需要的是获取创建 Range 对象所需的值startContainer
、和。是数字,所以它非常简单。容器是节点,不能直接保存为字符串,所以这是主要问题。您可以做的一件事是将密钥添加到您的 DOM 并保存密钥。但是,由于范围内的容器是文本节点,因此您需要保存文本节点的索引。像这样的东西应该允许使用递归函数用键标记 DOM:startOffset
endContainer
endOffset
Offsets
function addKey(element) {
if (element.children.length > 0) {
Array.prototype.forEach.call(element.children, function(each, i) {
each.dataset.key = key++;
addKey(each)
});
}
};
addKey(document.body);
完成此操作后,您可以将范围对象转换为可以保存为字符串的对象。像这样:
function rangeToObj(range) {
return {
startKey: range.startContainer.parentNode.dataset.key,
startTextIndex: Array.prototype.indexOf.call(range.startContainer.parentNode.childNodes, range.startContainer),
endKey: range.endContainer.parentNode.dataset.key,
endTextIndex: Array.prototype.indexOf.call(range.endContainer.parentNode.childNodes, range.endContainer),
startOffset: range.startOffset,
endOffset: range.endOffset
}
}
使用它,您可以将用户创建的每个选择保存到数组中。像这样:
document.getElementById('textToSelect').addEventListener('mouseup', function(e) {
if (confirm('highlight?')) {
var range = document.getSelection().getRangeAt(0);
selectArray.push(rangeToObj(range));
document.execCommand('hiliteColor', false, 'yellow')
}
});
要保存亮点,请将每个对象保存为 JSON。要对此进行测试,您可以从范围对象数组中获取 JSON 字符串。像这样(这是使用顶部的获取选择按钮):
document.getElementById('getSelectionString').addEventListener('click', function() {
alert('Copy string to save selections: ' + JSON.stringify(selectArray));
});
然后在加载空 HTML 时,您可以使用反向函数,该函数将从您保存在 JSON 中的对象创建范围。像这样:
function objToRange(rangeStr) {
range = document.createRange();
range.setStart(document.querySelector('[data-key="' + rangeStr.startKey + '"]').childNodes[rangeStr.startTextIndex], rangeStr.startOffset);
range.setEnd(document.querySelector('[data-key="' + rangeStr.endKey + '"]').childNodes[rangeStr.endTextIndex], rangeStr.endOffset);
return range;
}
因此,您可以将字符串中的范围数组转换为对象,然后转换为可以添加的范围对象。然后使用 execCommand,设置一些格式。像这样(这是使用顶部的设置选择按钮,您在刷新小提琴后执行此操作):
document.getElementById('setSelection').addEventListener('click', function() {
var selStr = prompt('Paste string');
var selArr = JSON.parse(selStr);
var sel = getSelection();
selArr.forEach(function(each) {
sel.removeAllRanges();
sel.addRange(objToRange(each));
document.execCommand('hiliteColor', false, 'yellow')
})
});
见:https ://jsfiddle.net/sek4tr2f/3/
请注意,在某些情况下这不起作用,主要的问题情况是用户在已突出显示的内容中选择内容。这些情况可以处理,但你需要更多的条件。