如何确定元素是否可以有html子元素?
只有Internet Explorer似乎具有元素属性:canHaveHtml
(MSDN,Dottoro)。我似乎无法找到其他浏览器中的任何内容来模拟它,除了使用具有标记名列表的正则表达式。有没有办法在Chrome,Firefox等中确定这一点?如何确定元素是否可以有html子元素?
例如有没有办法检查innerHTML
属性,并且这是100%等效的?
我似乎无法找到在其他浏览器的任何效仿,其他 比使用正则表达式与标记名的列表。
它可能看起来不优雅或聪明的,但创建一个白名单(或黑名单)是最简单,最快速,最可靠的方法。你不需要一个正则表达式;您可以创建一个简单的结构,如关联数组。
// blacklist approach
var noChildren = {
input: true,
meta: true,
br: true,
link: true,
img: true
// other properties here
};
function canHaveChildren(tagName) {
tagName = tagName.toLowerCase();
alert(noChildren[tagName] === undefined);
}
canHaveChildren("BR");
canHaveChildren("div");
演示:http://jsfiddle.net/FTbWa/
可重复使用的功能:Github Gist
此范例并非没有先例;它被用于许多脚本库和HTML解析器/消毒器。例如,查看jQuery的源代码,您会注意到很多元素特定的测试以及元素名称和属性名称的数组。
有什么元素可以和不可以有孩子的地方有确切的列表吗? – poby 2013-04-21 11:46:50
是的,这些都是在规范中明确定义的。这是一个很好的快速列表:http://dev.w3.org/html5/markup/elements.html所以这是:https://developer.mozilla.org/en-US/docs/HTML/HTML5/HTML5_element_list 。点击元素名称以查看它可以/不能包含的内容。 – 2013-04-21 11:48:35
对象文字和正则表白白名单之间的区别在哪里?正则表达式imho更具表现力,[大多更快](http://www.google.de/search?q=jsperf+regex+vs+lookup) – Bergi 2013-04-21 12:56:45
这里我假设如果元素没有innerHTML属性,它应该有一个值或一个src或一个类型属性。不能想到任何其他方式。您可以添加特定的TagName检查来处理下面的代码无法处理的特定情况。
function CheckInnerHTMLSupport(oElement)
{
var oDiv = document.createElement(oElement.tagName);
if('canHaveHTML' in oDiv)
{
return oDiv.canHaveHTML;
}
var bSupportsInnerHTML = oDiv.type === undefined && oDiv.value === undefined && oDiv.src === undefined;
return bSupportsInnerHTML;
}
这是不健壮的:画布,img,链接,元不被捕获,仅举几例。你最好查看规范并创建一个覆盖所有已知案例的方法。 – 2013-04-21 10:50:22
我相信'canvas'实际上可以包含孩子。 – ZER0 2013-04-21 10:56:44
我相信没有关于规格:
http://www.w3.org/TR/domcore/#concept-node-append
例如,在Firefox,Chrome和Safari,你可以真的喜欢<input>
节点添加到元素,例如:
var input = document.createElement("input");
var div = document.createElement("div");
div.textContent = 'hello';
console.log(input.outerHTML, input.childNodes.length);
input.appendChild(div);
console.log(input.outerHTML, input.childNodes.length);
他们只是没有呈现。但在这两种情况下,它们都被认为是input
节点的子节点。在Firefox的情况下,outerHTML
未更改,只有childNodes
长度报告1,在Chrome和Safari的情况下outerHTML
从<input>
更改为<input></input>
。 在Firefox中,与Safari和Chrome相反,innerHTML
实际上返回了子代的HTML,即使它未呈现并且在outerHTML
中也未返回。
更新: 作为@Bergi在@MårtenWikström回答指出,接近就像我做并没有真正运作良好,可以有内容,如textarea
,甚至title
,而不是HTML内容元素的前面。因此,更好的canHaveHTML
可能是类似的东西:
// Improving the `canHaveHTML` using `canHaveChildren`,
// using the approach shown by Mårten Wikström
function canHaveChildren(node) {
// Uses the native implementation, if any.
// I can't test on IE, so maybe it could be worthy to never use
// the native implementation to have a consistent and controlled
// behaviors across browsers. In case, just remove those two lines
if (node && node.canHaveChildren)
return node.canHaveChildren();
// Returns false if it's not an element type node; or if it has a end tag.
// Use the `ownerDocument` of the `node` given in order to create
// the node in the same document NS/type, rather than the current one,
// useful if we works across different windows/documents.
return node.nodeType === 1 && node.ownerDocument
.createElement(node.tagName).outerHTML.indexOf("></") > 0;
}
function canHaveHTML(node) {
// See comment in `canHaveChildren` about native impl.
if (node && node.canHaveHTML)
return node.canHaveHTML();
// We don't bother to create a new node in memory if it
// can't have children at all
if (!canHaveChildren(node))
return false;
// Can have children, then we'll check if it can have
// HTML children.
node = node.ownerDocument.createElement(node.tagName);
node.innerHTML = "<b></b>";
// if `node` can have HTML children, then the `nodeType`
// of the node just inserted with `innerHTML` has to be `1`
// (otherwise will be likely `3`, a textnode).
return node.firstChild.nodeType === 1;
}
测试在Firefox,Chrome和Safari浏览器;应涵盖所有节点和所有场景。
您可以使用以下函数来确定指定的元素是否可能有子项。
但是,正如ZER0所指出的,这可能更像是IE的canHaveChildren而不是canHaveHtml的替代品,因为它对任何“假定”不为空的标签名称返回true。
function canHaveHtml(tag) {
return document.createElement(tag).outerHTML.indexOf("></") > 0;
}
它使用的事实,新创建的元素,这是不能(或不应该)有内容,有outerHtml
没有结束标记。
例如:
document.createElement("input").outerHTML === "<input>"
和
document.createElement("div").outerHTML === "<div></div>"
您需要检查canHaveHtml属性的目的是什么? Manybe它可以使用不同的属性 – 2013-04-21 10:34:49
是不是可以将孩子添加到所有标签?因为它在html/xml中有效?这样做时你有错误吗? – 2013-04-21 10:35:11
@GrzegorzKaczan - ' foo'在HTML中无效。 – Quentin 2013-04-21 10:35:36