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

时间:2010-09-06 19:15:04

标签: javascript cross-browser getelementsbyclassname

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

简而言之,不同的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节点。

之前已经完成了(有点),但是这是我的镜头。

我的问题是,是否有一种很好的方法可以使用动态创建的元素来完成这项工作?似乎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,请)?

2 个答案:

答案 0 :(得分:5)

我认为你想要的东西可以通过原型Element interface来实现,比如

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

不要这样做。它在所有主流浏览器中都无法可靠地运行。

您在问题中的示例中所做的事情也是不可取的。您实际上正在扩展主机对象。请再次不要这样做

你将完全陷入那些陷阱Prototype ran into

我不想仅仅复制Kangax的文章,所以请阅读What’s wrong with extending the DOM

为什么你首先想要这个?你的目标是什么?

答案 1 :(得分: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);
    }
  }

}());