如何确定元素是否可以有html子元素?

pob*_*oby 14 javascript

只有Internet Explorer似乎具有元素属性:canHaveHtml(MSDN,Dottoro).除了使用带有标记名列表的正则表达式之外,我似乎无法在其他浏览器中找到任何模拟它的东西.有没有办法在Chrome,Firefox等中确定这一点?

例如,有没有办法检查innerHTML房产,这100%相当吗?

ZER*_*ER0 5

我相信没有关于这一点的规范:

\n\n

http://www.w3.org/TR/domcore/#concept-node-append

\n\n

例如,在 Firefox、Chrome 和 Safari 中,您实际上可以向元素添加节点,<input>例如:

\n\n
var input = document.createElement("input");\nvar div = document.createElement("div");\n\ndiv.textContent = \'hello\';\n\nconsole.log(input.outerHTML, input.childNodes.length);\n\ninput.appendChild(div);\n\nconsole.log(input.outerHTML, input.childNodes.length);\n
Run Code Online (Sandbox Code Playgroud)\n\n

它们只是没有被渲染。但在这两种情况下它们都被视为input节点的子节点。如果是 Firefox,则outerHTML不会更改,仅childNodes长度报告 1,如果是 Chrome 和 Safari ,则从outerHTML更改为<input><input></input>\n在 Firefox 中,与 Safari 和 Chrome 相反,innerHTML实际上返回子级的 HTML,即使它\未渲​​染且未返回outerHTML.

\n\n

更新:\n正如 @Bergi 在 @M\xc3\xa5rtenWikstr\xc3\xb6m 答案中指出的那样,像我之前所做的方法对于可以包含内容(例如textarea,甚至 )title但不是 HTML 内容的元素来说并不能很好地工作。因此,更好的canHaveHTML可能是这样的:

\n\n
// Improving the `canHaveHTML` using `canHaveChildren`,\n// using the approach shown by M\xc3\xa5rten Wikstr\xc3\xb6m\nfunction canHaveChildren(node) {\n  // Uses the native implementation, if any.\n  // I can\'t test on IE, so maybe it could be worthy to never use\n  // the native implementation to have a consistent and controlled\n  // behaviors across browsers. In case, just remove those two lines\n  if (node && node.canHaveChildren)\n    return node.canHaveChildren();\n\n  // Returns false if it\'s not an element type node; or if it has a end tag.\n  // Use the `ownerDocument` of the `node` given in order to create\n  // the node in the same document NS / type, rather than the current one,\n  // useful if we works across different windows / documents.\n  return node.nodeType === 1 && node.ownerDocument\n      .createElement(node.tagName).outerHTML.indexOf("></") > 0;\n}\n\nfunction canHaveHTML(node) {\n  // See comment in `canHaveChildren` about native impl.\n  if (node && node.canHaveHTML)\n    return node.canHaveHTML();\n\n  // We don\'t bother to create a new node in memory if it\n  // can\'t have children at all\n  if (!canHaveChildren(node))\n    return false;\n\n  // Can have children, then we\'ll check if it can have\n  // HTML children.\n  node = node.ownerDocument.createElement(node.tagName);\n\n  node.innerHTML = "<b></b>";\n\n  // if `node` can have HTML children, then the `nodeType`\n  // of the node just inserted with `innerHTML` has to be `1`\n  // (otherwise will be likely `3`, a textnode).\n  return node.firstChild.nodeType === 1;  \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 Firefox、Chrome 和 Safari 中测试;应该覆盖所有节点和所有场景。

\n


Mår*_*röm 5

您可以使用以下函数来确定命名元素是否可以有子元素。

然而,正如 ZER0 所指出的,这可能更像是 IE 的canHaveChildren而不是canHaveHtml的替代品,因为它对于“应该”不为空的任何标签名称返回 true。

function canHaveHtml(tag) { 
    return document.createElement(tag).outerHTML.indexOf("></") > 0; 
}
Run Code Online (Sandbox Code Playgroud)

它利用了这样一个事实:新创建的元素不能(或不应该)有内容,没有outerHtml结束标签。

例如:

document.createElement("input").outerHTML === "<input>"
Run Code Online (Sandbox Code Playgroud)

document.createElement("div").outerHTML === "<div></div>"
Run Code Online (Sandbox Code Playgroud)


Tim*_*ora 3

除了使用带有标记名列表的正则表达式之外,我似乎无法在其他浏览器中找到任何东西来模拟它。

它可能看起来不优雅或不聪明,但创建白名单(或黑名单)是最简单、最快、最可靠的方法。你不需要正则表达式;您可以使用简单的结构(例如关联数组)来创建。

// 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");
Run Code Online (Sandbox Code Playgroud)

演示: http: //jsfiddle.net/FTbWa/
可重用功能:Github Gist

这种范式并非没有先例。它被用在许多脚本库和 HTML 解析器/清理器中。例如,查看 jQuery 的源代码,您会注意到许多特定于元素的测试以及元素名称和属性名称的数组。