简体   繁体   English

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

[英]How to determine if element can have html children?

Only Internet Explorer seems to have the element property: canHaveHtml ( MSDN , Dottoro ). 只有Internet Explorer似乎具有element属性: canHaveHtmlMSDNDottoro )。 I can't seem to find anything in other browsers to emulate it, other than using a regex with a list of tagnames. 除了使用带有标记名列表的正则表达式之外,我似乎无法在其他浏览器中找到任何模拟它的东西。 Is there a way to determine this in Chrome, Firefox etc? 有没有办法在Chrome,Firefox等中确定这一点?

For example is there a way of checking for the innerHTML property and is this 100% equivalent? 例如,是否有一种检查innerHTML属性的方法,这是100%等效吗?

I believe there is no specifications about that: 我相信没有相关规范:

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

For instance, in Firefox, Chrome and Safari, you can actually add nodes to elements like <input> for example: 例如,在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);

They're just not rendered. 他们只是没有渲染。 But they're considered children of the input node in both case. 但在这两种情况下,它们都被视为input节点的子节点。 In case of Firefox the outerHTML is not changed, only the childNodes length reports 1, in case of Chrome and Safari the outerHTML changes from <input> to <input></input> . 在Firefox的情况下, outerHTML不会更改,只有childNodes长度报告1,在Chrome和Safari的情况下, outerHTML<input>更改为<input></input> In Firefox, as opposite of Safari and Chrome, innerHTML returns actually the children's HTML, even if it's not rendered and is not returned in outerHTML . 在Firefox中,与Safari和Chrome相反, innerHTML实际上返回了孩子们的HTML,即使它没有呈现,也没有在outerHTML返回。

Update : As @Bergi pointed out in @MårtenWikström answer, approaches like the previous I made doesn't really works well on element that can have content, like textarea , or even title , but not HTML content. 更新 :正如@Bergi在@MårtenWikström的回答中指出的那样,像我之前制作的那些方法在可以包含内容的元素(如textarea ,甚至是title ,但不是HTML内容)上效果不佳。 Therefore, a better canHaveHTML could be something like that: 因此,更好的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;  
}

Tested in Firefox, Chrome and Safari; 在Firefox,Chrome和Safari中测试过; that should cover all the nodes and all the scenarios. 应涵盖所有节点和所有场景。

You can use the following function to determine whether a named element may have children. 您可以使用以下函数来确定命名元素是否可能具有子元素。

However, as noted by ZER0, this is probably more like a replacement for IE's canHaveChildren rather than canHaveHtml , as it returns true for any tag name that is "supposed" to not be empty. 然而,正如ZER0所指出的,这可能更像是IE的canHaveChildren而不是canHaveHtml的替代品,因为它对于任何“假定”不为空的标记名称都返回true。

function canHaveHtml(tag) { 
    return document.createElement(tag).outerHTML.indexOf("></") > 0; 
}

It uses the fact that a newly created element, that cannot (or should not) have content, has outerHtml without an end tag. 它使用的事实是,新创建的元素(不能(或不应该)具有内容)具有不带结束标记的outerHtml

For example: 例如:

document.createElement("input").outerHTML === "<input>"

and

document.createElement("div").outerHTML === "<div></div>"

I can't seem to find anything in other browsers to emulate it, other than using a regex with a list of tagnames. 除了使用带有标记名列表的正则表达式之外,我似乎无法在其他浏览器中找到任何模拟它的东西。

It may not seem elegant or clever, but creating a whitelist (or blacklist) is the easiest, fastest, and most reliable approach. 它可能看起来不优雅或聪明,但创建白名单(或黑名单)是最简单,最快速,最可靠的方法。 You don't need a regular expression; 你不需要正则表达式; you can create use a simple structure such as an associative array. 您可以创建使用简单的结构,如关联数组。

// 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");

Demo: http://jsfiddle.net/FTbWa/ 演示: http//jsfiddle.net/FTbWa/
Reusable function: Github Gist 可重复使用的功能: Github Gist

This paradigm is not without precedence; 这种范式并非没有先例; it's used in many script libraries and HTML parsers/sanitizers. 它在许多脚本库和HTML解析器/清理程序中使用。 For example, look at the source of jQuery and you'll notice many element-specific tests and arrays of element names and attribute names. 例如,查看jQuery的源代码,您会注意到许多特定于元素的测试以及元素名称和属性名称的数组。

Here I am assuming that if the element does not have a innerHTML property, it should have a value or a src or a type property. 这里我假设如果元素没有innerHTML属性,它应该有一个值或src或type属性。 Cant think of any other way. 不能想到任何其他方式。 You could add specific TagName checks to handle specific cases which the code below fails to handle. 您可以添加特定的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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM