问
我可以使用 getElementsByTagName 选择多个标签吗?
一个
是的,但您必须多次使用 getElementsByTagName。
虽然您的示例仅指定了 Document.getElementsByTagName(),但我假设您也希望它与 element.getElementsByTagName() 一起使用。
关于HTMLCollection's的注意事项
- 它们不能被修改。
- 它们是一个live DOM 节点列表
- 只有三种方法可以直接自己创建
getElementsByTagName、getElementsByClassName和getElementsByTagNameNS
- 您可以创建一个对象,该对象可能具有 HTMLCollection 类型的属性,例如
nodeList.children
由于HTMLCollection's 无法修改,我们可以做的最好的事情是尽可能返回一个类似于HTMLCollection's 的对象,参见Create a HTMLCollection 或创建一个nodeList 并返回children 属性。
首先我们需要为我们的HTMLCollection
收集所有匹配的元素
最简单的方法是使用返回nodeList 的querySelectorAll 函数。
var nodeList = document.querySelectorAll(selector);
另一种方法是对每个标记使用getElementsByTagName 方法,将返回的 HTMLCollection 对象转换为数组,以便将它们合并在一起。
像这样。
var HTMLCollectionArray = [];
var names = selector.split(",");
for (var i = 0, n = names.length; i < n; i++){
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');
}
我们只希望Document 和Element 接口继承我们的新方法,因为它们调用的原型方法并不存在于所有Node 接口中。例如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');
}
请确保您不要尝试在不是Document 或Element 的任何节点上使用它。
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 createDocumentFragment = document.createDocumentFragment();
for (var i = 0; i < HTMLCollectionArray.length; i++) {
createDocumentFragment.appendChild(HTMLCollectionArray[i]);
};
HTMLCollection = createDocumentFragment.children;
return HTMLCollection;
*/
}
用法
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');