4

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

简而言之,不同的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,请)?

4

2 回答 2

5

我认为你想要的可以通过原型化Element接口来实现,比如

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

不要这样做。它不能在所有主流浏览器中可靠地工作。

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

您将完全陷入Prototype 遇到的那些陷阱。

我不想仅仅复制 Kangax 的文章,所以请阅读扩展 DOM 有什么问题

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

于 2010-09-06T23:10:03.257 回答
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);
    }
  }

}());
于 2010-09-07T00:15:03.960 回答