以下javascript(在Chrome控制台中运行)不能达到我的期望:
> var elem = document.createElement("foo");
undefined
> elem.innerHTML = "<tr></tr>"
"<tr></tr>"
> elem.outerHTML
"<foo></foo>"
<tr>
标记已消失!
这似乎与表相关的元素有关。使用<div>
或<span>
按预期工作。
我希望我正在做的事情是无效的,因为“foo”不是一个已知元素,并且可能与表相关的元素只能出现在a中。有趣的是,以下代码工作正常:
> var elem = document.createElement("foo"), tr = document.createElement("tr");
> elem.appendChild(tr);
> elem.outerHTML
"<foo><tr></tr></foo>"
所以看起来构造本身(<tr>
不在<table>
内)是允许的,但是使用innerHTML将它放在那里的方法不起作用 - 也许这可以通过一些html清理,它可以删除不严格的内容,而直接创建DOM节点则不需要进行相同的验证。
我的问题:有没有办法从字符串填充任意DOM节点而不会遇到这样的清理/验证问题?我的用例将结束具有完全有效的结构(我计划将其作为稍后的孩子),但是当我尝试构建各个部分时,浏览器正在阻止我。 / p>
听起来有点像DocumentFragment应该是我正在寻找的东西,但据我所知,这些只能以编程方式构建 - 它们不支持innerHTML。
我的用例是基于javascript的实时模板(即不输出html字符串,但实际的DOM节点)。所以要求是:
第二点是我遇到这个错误的方法。我的模板包含一个子模板。
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和amp;中都是一样的chrome,所以我不指望我只是遇到浏览器错误。
答案 0 :(得分:2)
不幸的是,您的一般问题的答案是否定的,没有办法使用innerHTML
添加任意不完整的HTML片段。我知道这不是你想听的答案,但就是这样。
关于innerHTML
最容易被误解的事情之一源于API的设计方式。它会使+
和=
运算符重载以执行DOM插入。这使得程序员认为它只是在进行字符串操作,而实际上innerHTML
的行为更像是函数而不是变量。如果innerHTML
的设计如下:
element.innerHTML('some <b>html</b> here');
遗憾的是,更改API为时已晚,因此我们必须明白它实际上是一个API,而不仅仅是一个属性/变量。
现在,了解innerHTML
所谓的“验证”行为。当您修改innerHTML
时,它会触发对浏览器的HTML编译器的调用。它是编译你的html文件/文件的相同编译器。 innerHTML
调用的HTML编译器没什么特别之处。因此,无论你对html文件做什么,都可以传递给innerHTML
(一个例外是嵌入式javascript不会被执行 - 可能出于安全原因)。
从浏览器开发人员的角度来看,这是有道理的。为什么在浏览器中包含两个单独的HTML编译器?特别是考虑到HTML编译器是巨大的,复杂的野兽。
缺点是不完整的HTML的处理方式与处理html文档的方式相同。如果<td>
元素不在表格内,大多数浏览器都会将其剥离(正如您自己观察到的那样)。这基本上就是你要做的 - 创建无效/不完整的HTML。
有两种解决方法:
从页面中提取表格,然后使用字符串处理(regex et.el.)将<td>
插入表格字符串,然后将innerHTML
整个表格重新插入页面。
解析插入的HTML字符串,如果发现任何<td>
或<tr>
(或<option>
)提取出html元素并使用DOM方法插入它。
不幸的是,两者都很痛苦。
答案 1 :(得分:0)
Mihai Stancu关于jquery的评论让我想到:如果你打电话给$("<tr></tr>")
,jquery肯定会管理这个。我知道jquery有一个看起来像单个标签的字符串的快捷方式,但它也适用于复杂的HTML。
所以我深入研究了jquery源代码,找到了票证:
它正在使用正则表达式来检测字符串中第一个标记的名称,然后使用此信息来确定它需要包含什么“上下文”,以便innerHTML进程将其视为有效。我认为这种技术应该适用于所有格式良好的输入。
我已将此代码用于独立函数,该函数将任意字符串转换为DOM节点: