Internet Explorer のみが element プロパティを持っているようです: canHaveHtml
( MSDN、Dottoro )。タグ名のリストで正規表現を使用する以外に、他のブラウザでエミュレートするものを見つけることができないようです。Chrome、Firefoxなどでこれを判断する方法はありますか?
たとえば、innerHTML
プロパティを確認する方法はありますか?これは 100% 同等ですか?
それについての仕様はないと思います:
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 でテスト済み。これは、すべてのノードとすべてのシナリオをカバーする必要があります。
タグ名のリストで正規表現を使用する以外に、他のブラウザでエミュレートするものを見つけることができないようです。
エレガントでも賢くもないように見えるかもしれませんが、ホワイトリスト (またはブラックリスト) を作成するのが最も簡単で、最速で、最も信頼できる方法です。正規表現は必要ありません。連想配列などの単純な構造を使用して作成できます。
// 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 のソースを見ると、多くの要素固有のテストと、要素名と属性名の配列に気付くでしょう。
ここで、要素に innerHTML プロパティがない場合は、値または 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;
}