简体   繁体   English

我可以使用 getElementsByTagName 选择多个标签吗?

[英]Can I select multiple tags using getElementsByTagName?

I'm using a javascript snippet in order for visitors to my site to increase the font size on all paragraphs using the following javascript:我正在使用 javascript 代码段,以便我网站的访问者使用以下 javascript 增加所有段落的字体大小:

function increaseFontSize() {  

    var paragraphs = document.getElementsByTagName('p'); 

    for(i=0;i<paragraphs.length;i++) {   

        if(paragraphs[i].style.fontSize) { 
            var s = parseInt(paragraphs[i].style.fontSize.replace("px",""));
        } else {   
            var s = 14;
        }

        if(s != max) {  
            s += 1; 
        } 
        paragraphs[i].style.fontSize = s+"px"
    } 
} 

How can I also include "li" to this code so that "p" and "li" are the selected elements that are affected?我怎样才能在此代码中包含“li”,以便“p”和“li”是受影响的选定元素?

I would also like to avoid adding a class or an id to my "li" or "ul".我还想避免在我的“li”或“ul”中添加一个类或一个 id。 Is there a way to select two tags at once?有没有办法一次选择两个标签?

No, you can't select multiple tags with a single call to getElementsByTagName .不,您不能通过一次调用getElementsByTagName来选择多个标签。 You can either do two queries using getElementsByTagName or use querySelectorAll .您可以使用getElementsByTagName或使用querySelectorAll执行两个查询。

JSFiddle JSFiddle

var elems = document.querySelectorAll('p,li')

A year late, but if you intend on using the desired functionality multiple times in your project, and you don't have access to querySelector() , it might be worth extending the Node object with a simple function:晚了一年,但如果您打算在项目中多次使用所需的功能,并且您无权访问querySelector() ,则可能值得使用一个简单的函数扩展Node对象:

JavaScript JavaScript

/**
 * @param {Array} tags - The array of tagNames to search for.
 * @return {Array}     - The elements with matching tagNames.
 */
Node.prototype.getElementsByTagNames = function (tags) {
    var elements = [];

    for (var i = 0, n = tags.length; i < n; i++) {
        // Concatenate the array created from a HTMLCollection object
        elements = elements.concat(Array.prototype.slice.call(this.getElementsByTagName(tags[i])));
    }

    return elements;
};

Working demo on JSFiddle. JSFiddle 上的工作演示。

All it does is iterating over an array of tag names, then getting the corresponding elements using getElementsByTagName() for each iteration.它所做的只是迭代一个标签名称数组,然后每次迭代都使用getElementsByTagName()获取相应的元素。

This can then of course be used on any element the same exact way you use similar functions - for example, getElementById() - on any Node object, you are not limited to document .这当然可以用在任何元素上,就像您在任何Node对象上使用类似函数一样——例如getElementById() ,您不仅限于document

Q

Can I select multiple tags using getElementsByTagName?我可以使用 getElementsByTagName 选择多个标签吗?

A一种

Yes, but you will have to use getElementsByTagName multiple times.是的,但您必须多次使用 getElementsByTagName。

Although your example only specifies Document.getElementsByTagName() I have assumed you would like this to work with element.getElementsByTagName() as well.尽管您的示例仅指定Document.getElementsByTagName()我假设您也希望它与 element.getElementsByTagName() 一起使用。

getElementsByTagName returns a HTMLCollection object so the ideal outcome would be a method which returns a HTMLCollection object of elements for all tag names provided. getElementsByTagName 返回一个HTMLCollection对象,因此理想的结果是一个方法,该方法为提供的所有标签名称返回元素的HTMLCollection对象。

Things to note about HTMLCollection's HTMLCollection 的注意事项

  • They cannot be modified.它们不能被修改。
  • They are a live list of DOM nodes它们是 DOM 节点的实时列表
  • There are only three ways to create one yourself directly getElementsByTagName , getElementsByClassName and getElementsByTagNameNS只有三种方法可以自己直接创建getElementsByTagNamegetElementsByClassNamegetElementsByTagNameNS
  • you can create an object which may have properties which are of type HTMLCollection eg nodeList.children您可以创建一个对象,该对象可能具有 HTMLCollection 类型的属性,例如nodeList.children

As HTMLCollection's cannot be modified the best we can do is either return an object which resembled a HTMLCollection's as much as possible, see Create a HTMLCollection or to create an nodeList and return the children property.由于HTMLCollection无法修改,我们能做的最好的事情是返回一个尽可能类似于HTMLCollection 的对象,请参阅创建 HTMLCollection或创建nodeList并返回children属性。

Firstly we need to collect all the matching elements for our HTMLCollection首先,我们需要为HTMLCollection收集所有匹配的元素

The simplest way would be to use the querySelectorAll function which returns a nodeList .最简单的方法是使用返回nodeListquerySelectorAll函数。

var nodeList = document.querySelectorAll(selector);

An alternative would be to use the getElementsByTagName method for each tag, convert the returned HTMLCollection object to an array so they can be merged together.另一种方法是对每个标签使用getElementsByTagName方法,将返回的 HTMLCollection 对象转换为数组,以便将它们合并在一起。

Like so .像这样。

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

The nodeList can also be converted to an array using the same method.也可以使用相同的方法将 nodeList 转换为数组。

HTMLCollectionArray = Array.prototype.slice.call(nodeList);

We can now either return all the elements as an array or try to return a HTMLCollection.我们现在可以将所有元素作为数组返回,也可以尝试返回 HTMLCollection。

If we were to return a HTMLCollection it would have to be either move or copy the elements to a single parentNode so we can access parentNode.children .如果我们要返回一个 HTMLCollection,它必须将元素移动或复制到单个 parentNode 以便我们可以访问parentNode.children

I found using document.createDocumentFragment works best.我发现使用document.createDocumentFragment效果最好。

var createDocumentFragment = document.createDocumentFragment();
for (var i = 0; i < HTMLCollectionArray.length; i++) {
    createDocumentFragment.appendChild(HTMLCollectionArray[i]);
};
HTMLCollection = createDocumentFragment.children; 
return HTMLCollection;

Although this would return the correct type(HTMLCollection) it does not return the actual state of the elements when the method was called.尽管这会返回正确的类型(HTMLCollection),但它不会在调用该方法时返回元素的实际状态。 The DOM has been modified to achieve this. DOM 已被修改以实现此目的。 Not a good idea.不是个好主意。

So this leaves us with making a Fake HTMLCollection所以这让我们需要制作一个 Fake 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;
}

Usage用法

var HTMLCollection = new MyHTMLCollection(elementsArray);

Now to piece it all together.现在把它们拼凑起来。

Ive also implemented a 'getElementsByClassNames' method and well as 'getElementsByTagNames' which both use the same core method getElementsBySelector .我还实现了一个“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');
}

We ONLY want the Document and Element interfaces to inherit our new methods because they call prototype methods which do not exist in all Node interfaces.我们只希望DocumentElement接口继承我们的新方法,因为它们调用的原型方法并不存在于所有Node接口中。 eg getElementsByClassName , querySelectorAll , etc.例如getElementsByClassNamequerySelectorAll等。

If you want to minify your code then you could use Node.prototype instead of stating Element.prototype.如果你想缩小你的代码,那么你可以使用 Node.prototype 而不是声明Element.prototype. and Document.prototype.Document.prototype.

Node.prototype.getElementsByTagNames = function(selector){
    return this.getElementsBySelector(selector, 'getElementsByTagName');
}
Node.prototype.getElementsByClassNames = function(selector){
    return this.getElementsBySelector(selector, 'getElementsByClassName');
}

Just make sure you don't try to use it on any node which isn't Document or Element .只要确保您不要尝试在任何不是DocumentElement 的节点上使用它。

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;
    */
}

Usage用法

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'); 

You can select multiple tags using getElementsByTagName for the purpose of having one iterable array, where results for multiple tags eg P and LI could be processed together.您可以使用 getElementsByTagName 选择多个标签以获得一个可迭代数组,其中多个标签(例如 P 和 LI)的结果可以一起处理。
It can't be done by one call to getElementsByTagName(), but it's possible to chain two getElementsByTagName() and avoid more complicated code or the use of the querySelectorAll().它不能通过一次调用 getElementsByTagName() 来完成,但可以链接两个 getElementsByTagName() 并避免更复杂的代码或使用 querySelectorAll()。

This is your whole example.这是你的整个例子。

function increaseFontSize() {  

    Array.from(document.getElementsByTagName('p'))
        .concat(Array.from(document.getElementsByTagName('li'))).forEach(el => {


            if(el.style.fontSize) { 
                var s = parseInt(el.style.fontSize.replace("px",""));
            } else {   
                var s = 14;
            }

            if(s != max) {  
                s += 1; 
            } 
            el.style.fontSize = s+"px"
    });
} 

Explanation:解释:
Array.from()
this is the official way how to make real array from a collection.这是如何从集合中制作真实数组的官方方法。
Some browsers might support forEach() on HTMLCollection , but it's not in specs.一些浏览器可能支持HTMLCollection上的forEach() ,但它不在规范中。
Even so, they probably don't support concat() method.尽管如此,他们可能不支持concat()方法。
Using from() will create a shallow copy of the collection.使用from()将创建集合的浅拷贝。
That's an advantage on HTMLCollection because items could be modified during iteration and modification to elements inside the array will still be a modification on original objects.这是HTMLCollection的一个优势,因为项目可以在迭代期间修改,对数组内元素的修改仍然是对原始对象的修改。

Now we have two standard arrays and can use concat() to join them and forEach() to iterate the joined result.现在我们有两个标准数组,可以使用concat()连接它们并forEach()迭代连接的结果。

This only works in Chrome , and is not mean as the solution but found as remarkable javascript behaviour:这仅适用于 Chrome ,并不意味着作为解决方案,而是发现了非凡的 javascript 行为:

document.getElementsByTagName('p' || 'li') //-> selects both P and LI elements.

It even works with html collections where you might only want to ONLY select elements that contain multiple types of tags at the same time.它甚至适用于您可能只想同时选择包含多种类型标签的元素的 html 集合。 That can be done like this eg:可以这样做,例如:

var table = document.getElementByID('myTable');
var rows = table.getElementsByTagName('tr');

rows[1].getElementsByTagName('input' && 'select') //-> select only when both input and select are present

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

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