Q
我可以使用getElementsByTagName选择多个标签吗?
A
是的,但您将不得不多次使用getElementsByTagName。
虽然您的示例仅指定了
Document.getElementsByTagName(), 但我假设您希望这也适用于element.getElementsByTagName()。
getElementsByTagName返回一个
HTMLCollection对象,因此理想的结果是一个方法,该方法返回所有提供的标记名称的元素的
HTMLCollection对象。
关于
HTMLCollection's需要注意的事项。
- 它们无法被修改。
- 它们是DOM节点的实时列表
- 只有三种方法可以直接创建一个,即
getElementsByTagName
、getElementsByClassName
和getElementsByTagNameNS
- 您可以创建一个对象,该对象可能具有类型为HTMLCollection的属性,例如
nodeList.children
由于HTMLCollection无法被修改,我们能做的最好的办法就是返回一个尽可能类似于HTMLCollection的对象,参见创建HTMLCollection,或者创建一个nodeList
并返回children
属性。
首先,我们需要收集所有匹配元素以获取我们的HTMLCollection
最简单的方法是使用
querySelectorAll函数,它返回一个
nodeList
。
var nodeList = document.querySelectorAll(selector)
另一种方法是对每个标签使用
getElementsByTagName
方法,将返回的 HTMLCollection 对象转换为数组,然后将它们合并在一起。
像这样。
var HTMLCollectionArray = []
var names = selector.split(",")
for (var i = 0, n = names.length
HTMLCollectionArray = HTMLCollectionArray.concat(Array.prototype.slice.call(document.getElementsByTagName(names[i])))
}
节点列表(nodeList)也可以使用相同的方法转换为数组。
HTMLCollectionArray = Array.prototype.slice.call(nodeList)
我们现在可以将所有元素作为数组返回,或者尝试返回HTMLCollection。
如果我们要返回HTMLCollection,就必须将元素移动或复制到单个parentNode,以便我们可以访问parentNode.children。
我发现使用document.createDocumentFragment效果最好。
var createDocumentFragment = document.createDocumentFragment();
for (var i = 0; i < HTMLCollectionArray.length; i++) {
createDocumentFragment.appendChild(HTMLCollectionArray[i]);
};
HTMLCollection = createDocumentFragment.children;
return HTMLCollection;
虽然这样可以返回正确的类型(HTMLCollection),但它并不返回方法被调用时元素的实际状态。DOM 已经被修改以实现这一点。这不是一个好主意。
因此,我们只能制作一个假的 HTMLCollection。
window.MyNodeList = function(elements) {
for ( var i = 0; i < elements.length; i += 1 ) {
this[i] = elements[i];
}
Object.defineProperty( this, 'length', {
get: function () {
return elements.length;
}
});
Object.freeze( this );
};
window.MyNodeList.prototype.item function ( i ) {
return this[i] != null ? this[i] : null;
}
window.MyHTMLCollection = function(elements) {
MyNodeList.call(this, elements);
}
MyHTMLCollection.prototype = Object.create(MyNodeList.prototype);
MyHTMLCollection.prototype.constructor = MyHTMLCollection;
window.MyHTMLCollection.prototype.namedItem = function ( name ) {
for ( var i = 0; i < this.length; i += 1 ) {
if ( this[i].id === name || this[i].name === name ) {
return this[i];
}
}
return null;
}
使用方法。
var HTMLCollection = new MyHTMLCollection(elementsArray)
现在把所有东西拼起来。
我还实现了一个“getElementsByClassNames”方法和一个“getElementsByTagNames”方法,它们都使用相同的核心方法
getElementsBySelector
。
Element.prototype.getElementsByTagNames = Document.prototype.getElementsByTagNames = function(selector){
return this.getElementsBySelector(selector, 'getElementsByTagName');
}
Element.prototype.getElementsByClassNames = Document.prototype.getElementsByClassNames = function(selector){
return this.getElementsBySelector(selector, 'getElementsByClassName');
}
我们只希望
文档和
元素接口继承我们的新方法,因为它们调用了不是所有
节点接口都存在的原型方法。例如:
getElementsByClassName
、
querySelectorAll
等。
如果您想要压缩您的代码,那么您可以使用Node.prototype而不是声明
Element.prototype.
和
Document.prototype.
。
Node.prototype.getElementsByTagNames = function(selector){
return this.getElementsBySelector(selector, 'getElementsByTagName');
}
Node.prototype.getElementsByClassNames = function(selector){
return this.getElementsBySelector(selector, 'getElementsByClassName');
}
请确保不要在任何不是
文档或
元素的节点上使用它。
Element.prototype.getElementsBySelector = Document.prototype.getElementsBySelector = function (selector, HTMLCollectionType) {
var HTMLCollectionArray = [];
if(typeof this.querySelectorAll !== 'undefined'){
var nodeList = this.querySelectorAll(selector);
HTMLCollectionArray = Array.prototype.slice.call(nodeList);
} else {
if(typeof HTMLCollectionType !=='undefined' && typeof this[HTMLCollectionType] !== 'undefined'){
var names = selector.split(",");
for (var i = 0, n = names.length; i < n; i++){
HTMLCollectionArray = HTMLCollectionArray.concat(Array.prototype.slice.call(this[HTMLCollectionType](names[i])));
}
}
}
return new MyHTMLCollection(HTMLCollectionArray);
}
使用方法
var element = document.getElementById('id');
element.getElementsbyClassNames('class1,class2,class2');
element.getElementsbyTagNames('li,div,p');
document.getElementsbyClassNames('class1,class2,class2');
document.getElementsbyTagNames('li,div,p');