Range
对象和document.execCommand
可以操作的选择很容易地。你的情况的主要问题是以文本格式保存范围对象。
基本上你需要的是获得startContainer
,startOffset
,endContainer
和endOffset
,它们是创建Range对象所需的值。 Offsets
是数字,所以它非常简单。容器是节点,你不能直接保存为字符串,所以这是主要问题。你可以做的一件事是添加键到你的DOM并保存密钥。但是,由于范围容器是文本节点,因此您需要保存文本节点的索引。这样的事情应该让来标记键的DOM,使用递归函数:
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字符串。像这样的(这是在顶部使用get Seletion按钮):
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;
}
因此,您可以将字符串中的范围数组转换为对象,然后将其转换为可添加的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/
注意,有些情况下,这将无法正常工作的情况下,主要是这样的(这是在顶部使用组选择按钮,刷新小提琴之后做到这一点)有问题的情况是用户在已经突出显示的内容中选择了内容。这些情况可以处理,但您需要更多条件。
你为什么不救突出显示的单词的数组索引,并且它们的长度? –
我同意@mohammedessam,创建一个数组,以便突出'xyz'的用户将数组添加'xyz',并且还会包含一个索引来指示'xyz'的具体实例是什么(即如果它是第3个'xyz'的实例,那么索引将是3. – tamak
我怀疑'innerHTML.indexOf(text)'会传递任何东西,更不用说索引了。'ReferenceError'更可能。 – KooiInc