14

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

例如,有没有办法检查innerHTML财产,这是否 100% 等效?

4

4 回答 4

5

我相信没有关于此的规范:

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 中测试;这应该涵盖所有节点和所有场景。

于 2013-04-21T11:11:10.537 回答
4

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

然而,正如 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>"
于 2013-04-21T11:20:42.140 回答
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");

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

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

于 2013-04-21T11:28:07.450 回答
0

这里我假设如果元素没有 innerHTML 属性,它应该有一个 value 或一个 src 或一个 type 属性。想不出别的办法。您可以添加特定的 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;
}
于 2013-04-21T10:46:38.060 回答