以下 javascript(在 chrome 控制台中运行)没有达到我的预期:
> var elem = document.createElement("foo");
undefined
> elem.innerHTML = "<tr></tr>"
"<tr></tr>"
> elem.outerHTML
"<foo></foo>"
<tr>
标签消失了!
这似乎特定于与表相关的元素。使用<div>
或<span>
按预期工作。
我希望我正在做的事情是无效的,因为“foo”不是已知元素,并且可能与表相关的元素只能出现在 . 有趣的是,以下代码可以正常工作:
> var elem = document.createElement("foo"), tr = document.createElement("tr");
> elem.appendChild(tr);
> elem.outerHTML
"<foo><tr></tr></foo>"
因此,似乎构造本身(<tr>
不在 a 内<table>
)是允许的,但是使用 innerHTML 将其放置在那里的方法不起作用 - 也许这会通过一些 html 清理,在创建 DOM 节点时删除不严格的东西直接不接受同样的验证。
我的问题:有没有办法从字符串中填充任意 DOM 节点而不会遇到此类清理/验证问题?我的用例最终会得到完全有效的结构(我计划稍后将其作为子级),但是当我尝试构建各个部分时,浏览器阻止了我。
听起来有点像 DocumentFragment 应该是我正在寻找的东西,但据我所知,它们只能以编程方式构造——它们不支持 innerHTML。
关于我为什么要这样做的一些背景:
我的用例是基于 javascript 的实时模板(即不输出 html 字符串,而是实际的 DOM 节点)。所以要求是:
- 必须允许模板输入是任意 HTML(这就是我使用 innerHTML 而不是以编程方式构造节点的原因)
- 必须可以创建子模板,然后将其附加到更大的文档中(这就是为什么我不能一次创建整个文件的原因)。
第二点是我是怎么遇到这个bug的。我的模板包含一个子模板。
var row = Html("<tr></tr>");
var table = Html(["<table><thead>", row, "</thead></table>"]);
我稍后会添加如下代码:
row.append(Html(["<td>", column.header, "</td>"]));
实际填充列。因此,当它完全构建时,html将是有效的。但在中间阶段,每个模板/片段都是在单个元素下构建的。这意味着模板如下:
Html(["Hello <span>", name, "</span>"]);
仍然作为单个节点出现(以便可以将它们作为单个实体进行操作):
<foo>Hello <span>bob</span></foo>
当模板在 内仅产生一个子节点时<foo>
,将删除外部节点。但是在施工过程中,row
上面的模板应该是这样的<foo><tr></tr></foo>
。由于我在使用 innerHTML 时看到的验证行为,它最终以<foo></foo>
.
我已经检查了所有代码在 Firefox 和 chrome 中的工作方式都相同,所以我不认为我只是遇到了浏览器错误。