修改每个可能的DOM元素的原型 [英] Modify prototypes of every possible DOM element

查看:134
本文介绍了修改每个可能的DOM元素的原型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新的标题,以更好地反映我想要做的事。



简而言之,不同的dom元素有不同的构造函数,所有共享一个共同的原型。我正在寻找一种方法来通过修改这些原型给每个DOM元素添加一个函数属性,但我不知道如何找到它们。



例如,我可以这样做:

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

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

增强(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;

//这是我想要的部分摆脱...
//我可以将getByClass添加到一个单独的原型
//在下面的某个对象中使用它

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

函数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);
}
}

}());

在脚本加载之前加载的内容效果很好,但是新的动态创建的元素a getElementsByClassName 方法。任何建议(除了setInterval,请))

解决方案

我想你可以通过原型实现 元素界面,例如

  Element.prototype.getElementsByClassName = function(){
/ *做一些魔法* /
};

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



你在问题​​中的例子中做什么也不可取。你实际上是扩展主机对象。同样,请不要这样做



您会遇到原型碰到了



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



为什么要这样做?您的目标是什么?


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. 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.

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. Can anyone think of a better way?

(Original question follows)

Goal - make getElementsByClassName work on any DOM node in any browser.

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?

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. Any suggestions (besides setInterval, please)?

解决方案

I think what you want can be achieved by prototyping the Element interface, like

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.

I don't want to merely copy Kangax' article, so please read What’s wrong with extending the DOM.

Why do you want this in the first place? What's your goal?

这篇关于修改每个可能的DOM元素的原型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆