Ottieni elementi per attributo quando querySelectorAll non è disponibile senza utilizzare le librerie?


123
<p data-foo="bar">

Come puoi fare l'equivalente a

document.querySelectorAll('[data-foo]')

dove querySelectorAll non è disponibile ?

Ho bisogno di una soluzione nativa che funzioni almeno in IE7. Non mi interessa IE6.


controlla la libreria di selezione javascript di sizzle.js
epoca

1
Bello sì, l'unica selezione che devo fare sono gli attributi dei dati, quindi stavo cercando di capire il modo più semplice per correggerlo senza inserire un intero motore di selezione come Sizzle. Ma è un buon punto per guardare nella fonte. A proposito, un altro ottimo motore di selezione è github.com/ded/qwery
ryanve,

@ryanve, grazie darò un'occhiata :)
epoca

La soluzione di lavoro che ho usato è in github.com/ryanve/dope/blob/master/dope.js nel metodo chiamato 'queryAttr'
ryanve

7
Lol, la tua domanda è la mia risposta. Quindi questo arriva con un'altra domanda. In quale situazione querySelectorAllnon è disponibile? note - I don't care all IE
vzhen

Risposte:


136

Potresti scrivere una funzione che esegua getElementsByTagName ('*') e restituisca solo quegli elementi con un attributo "data-foo":

function getAllElementsWithAttribute(attribute)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++)
  {
    if (allElements[i].getAttribute(attribute) !== null)
    {
      // Element exists with attribute. Add to array.
      matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

Poi,

getAllElementsWithAttribute('data-foo');

8
L'utilizzo != nullè il modo ideale (migliore del mio commento sopra) perché nella vecchia IE è possibile che getAttribute restituisca un valore il cui valore typeofè'number'
ryanve

1
Perché usare document.getElementsByTagName('*')invece di document.all?
Pedrozath

1
Perché non usare hasAttributepiuttosto che getAttribute() !== null, dal momento che vuoi solo verificare l'esistenza e non il suo valore?
rvighne

61

Uso

//find first element with "someAttr" attribute
document.querySelector('[someAttr]')

o

//find all elements with "someAttr" attribute
document.querySelectorAll('[someAttr]') 

per trovare elementi per attributo. Ora è supportato in tutti i browser pertinenti (anche IE8): http://caniuse.com/#search=queryselector


2
In che modo questo ha così tanti voti positivi quando la domanda richiede esplicitamente: "Ho bisogno di una soluzione nativa che funzioni almeno in IE7 ". In secondo luogo, quel collegamento afferma che il supporto inizia in IE11 anche se in realtà inizia da IE8 - forse questo dovrebbe essere scambiato con developer.mozilla.org/en-US/docs/Web/API/Element/… quindi supporta effettivamente la risposta. ..?
Zze

7
Il motivo di tutti i voti positivi, e il motivo per cui ho dato la risposta, è che questa domanda SO è molto vecchia, quindi quando cerchi come trovare elementi DOM trovi questa domanda molto in alto nei risultati di ricerca, e poiché è ciò che le persone stanno cercando di votare. Utilità> accuratezza storica. In secondo luogo il collegamento funziona ancora bene, è solo che caniuse.com ha nascosto i vecchi browser, se passi a "Utilizzo relativo" vedrai ancora i vecchi browser.
Pylinux

Ha funzionato perfettamente. Veloce e semplice
Dawson B

È il 2020. Questa dovrebbe essere la risposta accettata ora.
NearHuscarl

44

Ho giocato un po 'e sono finito con questa soluzione rozza:

function getElementsByAttribute(attribute, context) {
  var nodeList = (context || document).getElementsByTagName('*');
  var nodeArray = [];
  var iterator = 0;
  var node = null;

  while (node = nodeList[iterator++]) {
    if (node.hasAttribute(attribute)) nodeArray.push(node);
  }

  return nodeArray;
}

L'utilizzo è abbastanza semplice e funziona anche in IE8:

getElementsByAttribute('data-foo');
// or with parentNode
getElementsByAttribute('data-foo', document);

http://fiddle.jshell.net/9xaxf6jr/

Ma consiglio di usare querySelector/ Allper questo (e per supportare i browser meno recenti usa un polyfill ):

document.querySelectorAll('[data-foo]');

Sì, +1 per querySelectorAll. Un rapido test jsperf jsperf.com/custom-vs-selectorall-attributes mostra che è molto più veloce della risposta accettata ... sfortunatamente non è compatibile con IE 7 :(
Sebastien Daniel

11

Prova questo funziona

document.querySelector ( '[attributo = "valore"]')

esempio :

document.querySelector('[role="button"]')

5

Funziona anche questo:

document.querySelector([attribute="value"]);

Così:

document.querySelector([data-foo="bar"]);

2
Mancano le virgolette singole nel querySelector effettivo. Dovrebbe essere: document.querySelector('[data-foo="bar"]');
Brettins

1

Prova questo - ho leggermente cambiato le risposte sopra:

var getAttributes = function(attribute) {
    var allElements = document.getElementsByTagName('*'),
        allElementsLen = allElements.length,
        curElement,
        i,
        results = [];

    for(i = 0; i < allElementsLen; i += 1) {
        curElement = allElements[i];

        if(curElement.getAttribute(attribute)) {
            results.push(curElement);
        }
    }

    return results;
};

Poi,

getAttributes('data-foo');

3
Cosa hai cambiato e perché?
Artjom B.

1

Una piccola modifica sulla risposta di @kevinfahy , per consentire di ottenere l'attributo per valore se necessario:

function getElementsByAttributeValue(attribute, value){
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++) {
    if (allElements[i].getAttribute(attribute) !== null) {
      if (!value || allElements[i].getAttribute(attribute) == value)
        matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

0

Non utilizzare nel browser

Nel browser, usa document.querySelect('[attribute-name]').

Ma se stai effettuando dei test unitari e il tuo dom deriso ha un'implementazione di querySelector flakey, questo farà il trucco.

Questa è la risposta di @ kevinfahy, appena ridotta per essere un po 'con le funzioni di freccia grossa ES6 e convertendo l'HtmlCollection in un array al costo della leggibilità forse.

Quindi funzionerà solo con un transpiler ES6. Inoltre, non sono sicuro di quanto sarà performante con molti elementi.

function getElementsWithAttribute(attribute) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) !== null);
}

Ed ecco una variante che otterrà un attributo con un valore specifico

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.