修改每个可能的 DOM 元素的原型
更新了标题以更好地反映我正在尝试做的事情。
简而言之,不同的 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 之外)吗?
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)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为你想要的可以通过原型化 来实现
Element
接口,类似,但不要这样做。它不能在所有主要浏览器中可靠地工作。
您在问题的示例中所做的也是不可取的。您实际上是在扩展宿主对象。再次强调,请不要这样做。
您将完全陷入 Prototype 遇到的陷阱。
我不想仅仅复制 Kangax 的文章,所以请阅读 扩展 DOM 有什么问题。
你为什么首先想要这个?你的目标是什么?
I think what you want can be achieved by prototyping the
Element
interface, likebut 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?
这似乎有效,但它很丑陋。我想知道它在IE中是否有效?
This seems to work, but it's ugly. I wonder if it works in IE?