2010-09-06 59 views
4

更新後的標題更好地反映了我正在嘗試做的事情。修改每個可能的DOM元素的原型

簡而言之,不同的dom元素有不同的構造函數,它們似乎並不共享一個通用的原型。我正在尋找一種方法來通過修改這些原型來爲每個DOM元素添加一個函數屬性,但我不知道如何找到它們。

例如,我可以做這樣的事情:

function enhanceDom (tagNames, methods) { 
    var i=-1, tagName; 
    while (tagName=tagNames[++i]) { 
    var tag=document.createElement(tagName); 
    if (!(tag && tag.constructor)) continue; 
    for (var methodName in methods) { 
     tag.constructor.prototype[methodName]=methods[methodName]; 
    } 
    } 
} 

var thingsToEnhance = ['a','abbr','acronym','address'/* on and on... */]; 

enhance(thingsToEnhance, { 
    doStuff : function(){ 
    /* ... */ 
    }, 
    doOtherStuff : function(){ 
    /* ... */ 
    } 
    /* ... */ 
}); 

當然,我想這樣做沒有列出每一個html元素。任何人都可以想出更好的方法嗎?

(原題如下)

目標 -使任何一種瀏覽器的DOM節點上getElementsByClassName工作。

它已經完成之前(有點),但這是我的拍攝。

我現在的問題是,有沒有一種很好的方式使這個工作與動態創建的元素?看來,HTML DOM元素不共享可以添加getElementsByClassName的通用可預測原型......或者我錯過了什麼?

這是我到目前爲止(編輯 - 更新每討論)。

(function(){ 

    var fn = 'getElementsByClassName'; 
    // var fn = 'gEBCN'; // test 

    if (typeof document[fn] != 'undefined') return; 

    // This is the part I want to get rid of... 
    // Can I add getByClass to a single prototype 
    // somewhere below Object and be done with it? 

    document[fn]=getByClass; 
    withDescendants(document, function (node) { 
    node[fn]=getByClass; 
    }); 

    function withDescendants (node, callback, userdata) { 
    var nodes = node.getElementsByTagName('*'), i=-1; 
    while (node=nodes[++i]) { 
     callback(node, userdata); 
    } 
    return userdata; 
    } 

    function getByClass (className) { 
    return withDescendants(this, getMatches, { 
     query:new RegExp('(^|\\s+)' + className + '($|\\s+)'), 
     found:[] 
    }).found; 
    } 

    function getMatches (node, data) { 
    if (node.className && node.className.match(data.query)) { 
     data.found.push(node); 
    } 
    } 

}()); 

它運作良好的腳本加載之前加載的內容,但新的動態創建的元素不會得到一個getElementsByClassName方法。任何建議(除了setInterval,請)?

+0

是否有某些原因決定不使用jQuery這樣的框架?如果是這樣,你可能想在你的問題中聲明,否則你會得到很多「使用jQuery!」答案。 – 2010-09-06 19:19:16

+0

我希望很明顯,我不打算爲此使用jQuery。手指交叉。 – 2010-09-06 19:21:24

+1

@Greg在發佈的代碼中沒有JQuery代碼,並且沒有JQuery標記,我認爲就足夠了... – 2010-09-06 19:22:41

回答

5

我想你想通過原型的Element interface來實現,像

Element.prototype.getElementsByClassName = function() { 
    /* do some magic stuff */ 
}; 

不這樣做什麼。它無法在所有主流瀏覽器中可靠運行。

你在問題的例子中所做的是不可取的。你實際上在擴展主機對象。再次請不要這樣做

你會完全落入這些陷阱Prototype ran into

我不想僅僅複製Kangax的文章,所以請閱讀What’s wrong with extending the DOM

爲什麼你想要這個呢?你的目標是什麼?

+0

偉大的文章。我意識到修改主機對象的一些危險。此實驗的總體目標是創建一個兼容層,以便所有腳本都可以在單個瀏覽器上進行測試,並且無需修改即可跨瀏覽器工作。不是創建一個新的庫,只是爲了擴展沒有特定功能的瀏覽器,因此它們的工作方式與我們開發人員測試的瀏覽器相同。它只用於內部的東西(其中一些已經累積),而不是GP圖書館。 – 2010-09-07 00:03:57

+0

'元素'或HTMLElement可能是我在找的東西。對那個跨瀏覽器的支持太糟糕了。標明這是正確的。 – 2010-09-07 00:31:56

0

這似乎工作,但它很醜。我不知道它在IE中是否有效?

(function(){ 

    enhanceDom('a abbr acronym address applet area b base basefont bdo big blockquote body br button caption center cite code col colgroup dd del dfn dir div dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html i iframe img input ins isindex kbd label legend li link map menu meta noframes noscript object ol optgroup option p param pre q s samp script select small span strike strong style sub sup table tbody td textarea tfoot th thead title tr tt u ul var' 
    ,{ 
    getElementsByClassName : getByClass 
    /* , ... */ 
    }); 

    function enhanceDom (tagNames, methods) { 
    var i=-1, tagName; 
    if (tagNames==''+tagNames) { 
     tagNames=tagNames.split(' '); 
    } 
    for (var methodName in methods) { 
     setIfMissing(document, methodName, methods[methodName]); 
     while (tagName=tagNames[++i]) { 
     var tag=document.createElement(tagName); 
     if (tag || !tag.constructor) continue; 
     var proto=tag.constructor.prototype; 
     setIfMissing(proto, methodName, methods[methodName]); 
     } 
    } 
    } 

    function setIfMissing (obj, prop, val) { 
    if (typeof obj[prop] == 'undefined') { 
     obj[prop]=val; 
    } 
    } 

    function withDescendants (node, callback, userdata) { 
    var nodes=node.getElementsByTagName('*'), i=-1; 
    while (node=nodes[++i]) { 
     callback(node, userdata); 
    } 
    return userdata; 
    } 

    function getByClass (className) { 
    return withDescendants(this, getMatches, { 
     query:new RegExp('(^|\\s+)' + className + '($|\\s+)'), 
     found:[] 
    }).found; 
    } 

    function getMatches (node, data) { 
    if (node.className && node.className.match(data.query)) { 
     data.found.push(node); 
    } 
    } 

}());