简体   繁体   English

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

[英]Modify prototypes of every possible DOM element

Updated title to better reflect what I'm trying to do. 更新标题以更好地反映我正在尝试做的事情。

In short, there are different constructors for different dom elements, and they don't seem to all share a common prototype. 简而言之,不同的dom元素有不同的构造函数,它们似乎并不共享一个共同的原型。 I'm looking for a way to add a function property to every DOM element by modifying these prototypes, but I'm not sure how to find them. 我正在寻找一种通过修改这些原型为每个DOM元素添加一个函数属性的方法,但我不知道如何找到它们。

For example, I could do something like this: 例如,我可以这样做:

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(){
    /* ... */
  } 
  /* ... */
});

Of course, I'd like to do this without listing every single html element. 当然,我想在没有列出每个单独的html元素的情况下这样做。 Can anyone think of a better way? 谁能想到更好的方法?

(Original question follows) (原始问题如下)

Goal - make getElementsByClassName work on any DOM node in any browser. 目标 -使getElementsByClassName可以在任何浏览器中的任何DOM节点上运行。

It's been done before (sort of), but here's my shot at it. 它已经完成了(有点),但这是我的镜头。

The question I have is, is there a good way to make this work with dynamically created elements? 我的问题是,有一个很好的方法来使用动态创建的元素吗? It seems that HTML DOM elements don't share a common predictable prototype where getElementsByClassName could be added... Or am I missing something? 似乎HTML DOM元素不共享可以添加getElementsByClassName的公共可预测原型......或者我错过了什么?

Here's what I've got so far ( edit - updated per discussion ). 这是我到目前为止所做的( 编辑 - 每次讨论更新 )。

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

}());

It works well on content loaded before the script loads, but new dynamically-created elements won't get a getElementsByClassName method. 它适用于在加载脚本之前加载的内容,但新动态创建的元素不会获得getElementsByClassName方法。 Any suggestions (besides setInterval, please)? 有任何建议(除了setInterval,请)?

I think what you want can be achieved by prototyping the Element interface , like 我认为你想要的东西可以通过原型化Element接口来实现,比如

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

but don't do this . 不要这样做 It doesn't work reliably in all major browsers. 它在所有主流浏览器中都无法可靠地运行。

What you're doing in the example in your question is not advisable, too. 您在问题中的示例中所做的事情也是不可取的。 You're actually extending host objects. 您实际上正在扩展主机对象。 Again, please don't do this . 再说一遍,请不要这样做

You'll fall in exactly those pitfalls Prototype ran into . 你将陷入Prototype遇到的那些陷阱。

I don't want to merely copy Kangax' article, so please read What's wrong with extending the DOM . 我不想仅仅复制Kangax的文章,所以请阅读扩展DOM有什么问题

Why do you want this in the first place? 你为什么一开始想要这个? What's your goal? 你的目标是什么?

This seems to work, but it's ugly. 这似乎有效,但它很难看。 I wonder if it works in IE? 我想知道它是否适用于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);
    }
  }

}());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM