【问题标题】:Can I select multiple tags using getElementsByTagName?我可以使用 getElementsByTagName 选择多个标签吗?
【发布时间】:2014-01-17 18:42:00
【问题描述】:

我正在使用 javascript sn-p,以便我网站的访问者使用以下 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"
    } 
} 

如何在此代码中也包含“li”,以便“p”和“li”成为受影响的选定元素?

我还想避免在我的“li”或“ul”中添加类或 id。有没有办法一次选择两个标签?

【问题讨论】:

  • 我不知道为什么人们会尽量避免添加类和 ID,这些都是为了提供帮助。您应该避免添加 太多 类,但一个就可以了。

标签: javascript html getelementsbytagname


【解决方案1】:

不,您不能通过一次调用 getElementsByTagName 来选择多个标签。您可以使用getElementsByTagNamequerySelectorAll 执行两个查询。

JSFiddle

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

【讨论】:

  • document.querySelectorAll('input,textarea,select') - 非常适合表单 - 谢谢
  • 我建议你将“不,你不能”改为“还有另一种方法可以做到这一点”。
  • getElementsByTagName 支持正则表达式。所以,是的,你可以!
  • @barwnikk 这是 w3c 和 whatwg 规范,您不能根据它们使用正则表达式 w3.org/TR/DOM-Level-3-Core/core.html#ID-1938918D dom.spec.whatwg.org/#dom-element-getelementsbytagname
  • @Bitterblue 问题显然是在询问您是否可以在 single 调用中做到这一点。非常明显,您可以通过两次调用来完成。
【解决方案2】:

晚了一年,但如果您打算在项目中多次使用所需的功能,并且您无权访问 querySelector(),则可能值得使用 simple 扩展 Node 对象 功能:

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.

它所做的只是遍历一个标签名称数组,然后在每次迭代中使用getElementsByTagName() 获取相应的元素。

这当然可以用在 any 元素上,就像你使用类似函数一样 - 例如,getElementById() - 在任何 Node 对象上,你不限于 @987654328 @。

【讨论】:

  • 我对此做了一点改动,其中 tags 是一个逗号分隔的字符串(即“input,textarea”)并在内部运行 tags.split(",") 。这样,它就像 getElementsByTagName 一样运行。这是一个很好的答案。
【解决方案3】:

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

一个

是的,但您必须多次使用 getElementsByTagName。

虽然您的示例仅指定了 Document.getElementsByTagName(),但我假设您也希望它与 element.getElementsByTagName() 一起使用。

关于HTMLCollection's的注意事项

  • 它们不能被修改。
  • 它们是一个live DOM 节点列表
  • 只有三种方法可以直接自己创建getElementsByTagNamegetElementsByClassNamegetElementsByTagNameNS
  • 您可以创建一个对象,该对象可能具有 HTMLCollection 类型的属性,例如 nodeList.children

由于HTMLCollection's 无法修改,我们可以做的最好的事情是尽可能返回一个类似于HTMLCollection's 的对象,参见Create a HTMLCollection 或创建一个nodeList 并返回children 属性。

首先我们需要为我们的HTMLCollection

收集所有匹配的元素

最简单的方法是使用返回nodeListquerySelectorAll 函数。

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

我们只希望DocumentElement 接口继承我们的新方法,因为它们调用的原型方法并不存在于所有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');
}

请确保您不要尝试在不是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;
    */
}

用法

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

【讨论】:

    【解决方案4】:

    您可以使用 getElementsByTagName 选择多个标签,以获得一个可迭代数组,其中多个标签的结果,例如P和LI可以一起处理。
    不能通过一次调用 getElementsByTagName() 来完成,但可以链接两个 getElementsByTagName() 并避免更复杂的代码或使用 querySelectorAll()。

    这是你的整个例子。

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

    说明:
    Array.from()
    这是从集合中制作真正数组的官方方法。
    某些浏览器可能在 HTMLCollection 上支持 forEach(),但不在规范中。
    即便如此,他们可能不支持concat() 方法。
    使用 from() 将创建集合的浅表副本。
    这是HTMLCollection 的一个优势,因为可以在迭代期间修改项目 并且对数组内元素的修改仍然是对原始对象的修改。

    现在我们有两个标准数组,可以使用concat() 连接它们,使用forEach() 迭代连接的结果。

    【讨论】:

      【解决方案5】:

      这仅在 Chrome 中有效,并不意味着作为解决方案,而是发现了非凡的 javascript 行为:

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

      它甚至适用于 html 集合,您可能只想同时选择包含多种类型标签的元素。可以这样做,例如:

      var table = document.getElementByID('myTable');
      var rows = table.getElementsByTagName('tr');
      
      rows[1].getElementsByTagName('input' && 'select') //-> select only when both input and select are present
      

      【讨论】:

      • 我怀疑它是否有效(对我来说肯定没有)。 'p' || 'li' 总是返回 'p',因为它强制转换为 true,而 'input' &amp;&amp; 'select' 总是返回 'select',原因相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多