2013-04-21 204 views
14

只有Internet Explorer似乎具有元素屬性:canHaveHtmlMSDNDottoro)。我似乎無法找到其他瀏覽器中的任何內容來模擬它,除了使用具有標記名列表的正則表達式。有沒有辦法在Chrome,Firefox等中確定這一點?如何確定元素是否可以有html子元素?

例如有沒有辦法檢查innerHTML屬性,並且這是100%等效的?

+0

您需要檢查canHaveHtml屬性的目的是什麼? Manybe它可以使用不同的屬性 – 2013-04-21 10:34:49

+0

是不是可以將孩子添加到所有標籤?因爲它在html/xml中有效?這樣做時你有錯誤嗎? – 2013-04-21 10:35:11

+1

@GrzegorzKaczan - ' foo'在HTML中無效。 – Quentin 2013-04-21 10:35:36

回答

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的源代碼,您會注意到很多元素特定的測試以及元素名稱和屬性名稱的數組。

+0

有什麼元素可以和不可以有孩子的地方有確切的列表嗎? – poby 2013-04-21 11:46:50

+0

是的,這些都是在規範中明確定義的。這是一個很好的快速列表: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

+0

對象文字和正則表白白名單之間的區別在哪裏?正則表達式imho更具表現力,[大多更快](http://www.google.de/search?q=jsperf+regex+vs+lookup) – Bergi 2013-04-21 12:56:45

0

這裏我假設如果元素沒有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; 
} 
+3

這是不健壯的:畫布,img,鏈接,元不被捕獲,僅舉幾例。你最好查看規範並創建一個覆蓋所有已知案例的方法。 – 2013-04-21 10:50:22

+1

我相信'canvas'實際上可以包含孩子。 – ZER0 2013-04-21 10:56:44

4

我相信沒有關於規格:

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瀏覽器;應涵蓋所有節點和所有場景。

3

您可以使用以下函數來確定指定的元素是否可能有子項。

但是,正如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>" 
+0

似乎不適用於'textarea' ... – Bergi 2013-04-21 12:43:57

+0

不,它實際上只測試元素是否有內容(不應該爲空)。 Textareas可能有內容。所以根據使用情況它可能有用也可能不會有幫助。 – 2013-04-21 12:49:35

+0

啊,我明白了。我認爲OP要求提供HTML *元素*內容(aka * children *),而不是* text *內容(如textareas,titles,scripts,styles)。不知道什麼IE'canHaveHtml'的功能... – Bergi 2013-04-21 13:01:08

相關問題