我正在编写一个模块,允许用户选择HTML文档的一部分。要使内部工作正常,我将所选内容的Range
扩展为有效的HTML代码段。
对于B是A的后代的情况,我找到B的祖先,它是A的子节点,并且想要使用setEndAfter将范围设置为在该节点之后结束。这就是我现在所拥有的:
var closestChild = function (node, descendant) {
var parent;
if (descendant.parentElement) {
parent = descendant.parentElement;
if ( node === parent ) {
return descendant;
}
return closestChild(node, parent);
}
return false;
}
var legalRange = function (range) {
var newRange = range.cloneRange(),
child;
if (range.startContainer === range.endContainer) {
return newRange;
}
child = closestChild(range.startContainer.parentElement, range.endContainer.parentElement);
if (child) {
newRange.setEndAfter(child);
return newRange;
}
return null;
};
但是当我尝试设置终点时,这会抛出INVALID_NODE_TYPE_ERR: DOM Range Exception 2
。我也尝试使用parentNode而不是parentElement,抛出相同的异常。如果我使用setEnd(),这不是问题。我应该通过哪些类型的节点来实现这一目标。
PS:事实证明代码在FireFox中有效,所以现在我的问题出在Safari和Chrome上。
答案 0 :(得分:1)
我找到了解决方案。 当我设置我的测试用例时,我没有将元素添加到文档中。如果节点不是文档的一部分,那么当使用setEndAfter时,Chrome和Safari似乎将节点视为无效。
答案 1 :(得分:0)
正如Eivind所回答的,问题是用于设置范围位置的节点未附加到文档。因此,一种解决方案是在设置范围位置之前附加它。
另一种解决方案是,如果由于某种原因无法将节点附加到DOM,则可以使用setStart()
和setEnd()
。
// Instead of `range.setStartBefore(node)`
var parent = node.parent;
range.setStart(parent, Array.from(parent.childNodes).indexOf(node))
// Instead of `range.setStartAfter(node)`
var parent = node.parent;
range.setStart(parent, Array.from(parent.childNodes).indexOf(node) + 1)
// Instead of `range.setEndBefore(node)`
var parent = node.parent;
range.setEnd(parent, Array.from(parent.childNodes).indexOf(node))
// Instead of `range.setEndAfter(node)`
var parent = node.parent;
range.setEnd(parent, Array.from(parent.childNodes).indexOf(node) + 1)
注意:Internet Explorer中不支持Array.from(arrayLike)
< = 11.使用Array.prototype.slice.call(arrayLike)
代替您需要IE支持。