代码之家  ›  专栏  ›  技术社区  ›  Dagg Nabbit

修改每个可能的DOM元素的原型

  •  4
  • Dagg Nabbit  · 技术社区  · 14 年前

    更新标题以更好地反映我正在努力做的事情。

    简而言之,对于不同的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元素。有人能想出更好的办法吗?

    (原始问题如下)

    目标- getElementsByClassName 在任何浏览器中的任何DOM节点上工作。

    以前也做过(有点),但这是我的尝试。

    GetElementsByClass名称

    这是我目前掌握的情况( 编辑 ).

    (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);
        }
      }
    
    }());
    

    它在加载脚本之前加载的内容上工作得很好,但是动态创建的新元素将不会获得 方法。有什么建议吗(除了setInterval之外)?

    2 回复  |  直到 14 年前
        1
  •  5
  •   Marcel Korpel    14 年前

    我认为你想要的可以通过原型设计来实现 Element interface

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

    但是 别这样

    你在问题的例子中所做的也是不可取的。实际上是在扩展宿主对象。请再说一遍 别这样

    你会落入那些陷阱 Prototype ran into

    我不想只抄袭Kangax的文章,所以请阅读 What’s wrong with extending the DOM .

        2
  •  0
  •   Dagg Nabbit    14 年前

    这似乎管用,但很难看。我想知道它是否适用于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);
        }
      }
    
    }());