我需要替换每个带有跨距的兄弟的#text,以便它们有id。以下代码应该这样做,但由于某种原因,它会导致许多文档重塑:文档的一部分移动,页面改变其外观。
var eltId = 0;
function genEltId() {
return "my-id-" + ++eltId;
}
function hashTextsToSpans(elt) {
for (var i in elt.childNodes) {
var eltChild = elt.childNodes[i];
if (eltChild.nodeName == "#text" && elt.childNodes.length > 1) {
// #text is one of multiple childs
var eltDiv = document.createElement("span");
eltDiv.setAttribute("id", genEltId());
elt.replaceChild(eltDiv, eltChild);
eltDiv.appendChild(eltChild);
} else {
if (eltChild.nodeName != "IFRAME") {
hashTextsToSpans(eltChild);
}
}
}
}
function onKeyPress(e) {
if (e.keyCode == 105) {
// key I
hashTextsToSpans(document.body);
}
}
window.parent.addEventListener("keypress", onKeyPress);
例如,将其注入chrome(使用" cjs" addon)注入https://en.wikipedia.org/wiki/Linux,按" i",然后观察页面重塑。
有什么问题? Aren&#tt #text并跨越两个内联元素,并且当文本相同且span没有样式时应该以相同的方式显示?
假设:没有iframe元素,没有其他javascript同时操纵DOM树。
答案 0 :(得分:1)
问题在于,在HTML中,许多元素限制允许它们包含哪些类型的子节点。
例如,列表元素(例如ul
或ol
)只能包含li
个元素和空白(仅限空白)文本节点。当您在跨度中包装此类空白文本节点时,该页面突然不符合标准。
在您链接到的Wikipedia页面的特定情况下,原始页面的文本节点仅包含表格的tr
和td
元素之间的空格。当您的脚本运行时,这些文本节点将成为跨度,但不允许在表中包含tr
和td
元素之外的元素。因此,这会导致大多数浏览器自动将幻像列插入到表中,从而弄乱了布局。
作为快速修复,您可以忽略仅包含空格的文本节点。如果您使用TreeWalker API,通过将以下函数作为过滤器传递,这是微不足道的:
node => /\S/.test(node.nodeValue) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
作为一个更长期的修复,您可能需要查看HTML5 spec以确定哪些元素可以包含span节点,并相应地编写脚本。