javascript - forEach on querySelectorAll no funciona en los navegadores recientes de Microsoft
arrays internet-explorer (3)
Bien, comencemos desde aquí, en JavaScript, tenemos algunos casos que lo llamamos tipo Array , lo que significa que incluso parece una matriz, no es una matriz real ...
Por ejemplo, argumentos en función o en su caso Nodelist ...
Incluso todos los navegadores modernos entienden cuál le gustaría cambiar a Array y funcionan bien, en IE y algunos otros navegadores no es compatible con las funciones de matriz en Nodelist, por ejemplo ...
Entonces, si admite una amplia gama de navegadores, es mejor convertirlos a una matriz antes de realizar cualquier actividad en ellos ...
Hay pocas formas de convertir valores similares a Array en Array real ...
Uno ampliamente utilizado en ES5 es esta estructura:
Array.prototype.slice.call (YourNodeList);
Entonces puedes hacer:
var allDivs = document.querySelectorAll("div");
var allRealDivsArray = Array.prototype.slice.call(allDivs);
Pero si usa ES6, hay formas aún más ingeniosas de hacerlo, solo asegúrese de convertirlos a ES5 usando babel, por ejemplo, ya que esos navegadores antiguos que no admiten bucles en forma de matriz, tampoco admitirán ES6 con seguridad. ..
Dos formas muy comunes de hacerlas son:
1) Usando Array.from
const allDivs = document.querySelectorAll("div");
const allRealDivsArray = Array.from(allDivs);
2) Utilizando [... Array]
const allDivs = document.querySelectorAll("div");
const allRealDivsArray = [...allDivs];
Estoy haciendo un script para elegir un producto (colores, etc.), que funciona en todos los navegadores, excepto en Internet Explorer (11) y Edge .
array.forEach()
las opciones de cada parámetro en una matriz y les aplico una función con el método
array.forEach()
.
Ejemplo para el parámetro de color:
var color_btns = document.querySelectorAll(''#color > p'');
color_btns.forEach(function(color) {
color.onclick = function () {
color_btns.forEach(function(element) {
if (element.classList.contains(''selected'')) {
element.classList.remove(''selected'');
}
});
color.classList.add(''selected'');
document.querySelector(''#f_color'').value = color.dataset.id;
};
});
Obtengo el siguiente resultado en la consola de IE y Edge :
El objeto no admite la propiedad o el método ''forEach''
Después de buscar sobre el problema, aprendí que
IE 9 y versiones posteriores
deberían admitir esta función.
Traté de definir la función por mí mismo sin éxito.
Cuando registro la función, se define como una función (con "
[native code]
" dentro).
.forEach
cada
.forEach
por un
for
y funciona bastante bien,
- pero ¿cómo puedo hacer que funcione?
-
¿Existe un uso específico de
forEach()
para Internet Explorer y Edge ?
Pensé que era
Array.prototype.forEach
y que las versiones recientes de IE (y todas las versiones de Edge) lo tenían ...?
El valor de retorno de
.querySelectorAll()
no es una matriz, es una
NodeList
.
Eso solo se obtuvo recientemente para cada
forEach
(y compatibilidad con el protocolo de
iteración
de JavaScript, lo que le permite usarlos como objetivos de notación
for-of
y spread).
Puede
forEach
fácilmente para cada
forEach
fácilmente:
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
// Yes, there''s really no need for `Object.defineProperty` here
NodeList.prototype.forEach = Array.prototype.forEach;
}
La asignación directa está bien en este caso, porque
enumerable
,
configurable
y
writable
debería ser todo
true
y es una propiedad de valor.
(La
true
enumerable
me sorprendió, pero así es como se define de forma nativa en Chrome, Firefox, Edge y Safari).
Cuando
NodeList
llegó a
forEach
, también se volvió
iterable
, lo que significa que puede recorrer el contenido de una
NodeList
través
for-of
bucles
for-of
, y usar una
NodeList
en otros lugares donde se espera un iterable (por ejemplo, en notación extendida en un inicializador de matriz) .
En la práctica, es probable que un navegador que tiene características que usan iterabilidad (como
for-of
loops) también proporcione estas características de
NodeList
, pero para asegurarse de que (tal vez esté transpilando e incluyendo un polyfill para
Symbol
), necesita hacer una segunda cosa: agregar una función a su propiedad
Symbol.iterator
que crea un iterador:
if (typeof Symbol !== "undefined" && Symbol.iterator && typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype[Symbol.iterator]) {
Object.defineProperty(NodeList.prototype, Symbol.iterator, {
value: Array.prototype[Symbol.itereator],
writable: true,
configurable: true
});
}
Haciendo ambos juntos:
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
// Yes, there''s really no need for `Object.defineProperty` here
NodeList.prototype.forEach = Array.prototype.forEach;
if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) {
Object.defineProperty(NodeList.prototype, Symbol.iterator, {
value: Array.prototype[Symbol.itereator],
writable: true,
configurable: true
});
}
}
Aquí hay un ejemplo en vivo usando ambos, intente esto en (por ejemplo) IE11 (aunque solo demostrará para cada
forEach
), en el que
NodeList
no tiene estas características de forma nativa:
// Using only ES5 features so this runs on IE11
function log() {
if (typeof console !== "undefined" && console.log) {
console.log.apply(console, arguments);
}
}
if (typeof NodeList !== "undefined" && NodeList.prototype) {
// forEach
if (!NodeList.prototype.forEach) {
// Yes, there''s really no need for `Object.defineProperty` here
console.log("Added forEach");
NodeList.prototype.forEach = Array.prototype.forEach;
}
// Iterability
if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) {
console.log("Added Symbol.iterator");
Object.defineProperty(NodeList.prototype, Symbol.iterator, {
value: Array.prototype[Symbol.itereator],
writable: true,
configurable: true
});
}
}
log("Testing forEach");
document.querySelectorAll(".container div").forEach(function(div) {
var html = div.innerHTML;
div.innerHTML = html[0].toUpperCase() + html.substring(1).toLowerCase();
});
// Iterable
if (typeof Symbol !== "undefined" && Symbol.iterator) {
// Using eval here to avoid causing syntax errors on IE11
log("Testing iterability");
eval(
''for (const div of document.querySelectorAll(".container div")) { '' +
'' div.style.color = "blue"; '' +
''}''
);
}
<div class="container">
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
</div>
La
HTMLCollection
devuelta por
getElementsByTagName
(y varias otras API antiguas) no se define como iterable, pero si lo desea, también puede hacer esto para
HTMLCollection
.
Aquí hay un bucle haciendo boty
NodeList
(si es necesario) y
HTMLCollection
(si es necesario):
for (const ctor of [typeof NodeList !== "undefined" && NodeList, typeof HTMLCollection !== "undefined" && HTMLCollection]) {
if (ctor && ctor.prototype && !ctor.prototype.forEach) {
// (Yes, there''s really no need for `Object.defineProperty` here)
ctor.prototype.forEach = Array.prototype.forEach;
if (typeof Symbol !== "undefined" && Symbol.iterator && !ctor.prototype[Symbol.iterator]) {
Object.defineProperty(ctor.prototype, Symbol.iterator, {
value: Array.prototype[Symbol.itereator],
writable: true,
configurable: true
});
}
}
}
Solo tenga en cuenta que
HTMLCollection
está
HTMLCollection
, por lo que los cambios que realice en el DOM que afectan lo que está en la colección se reflejarán en la colección de inmediato, lo que podría dar lugar a un comportamiento sorprendente.
(
NodeList
es una colección desconectada, por lo que ese comportamiento no ocurre).
Si bien puede parecer una matriz, en realidad es una NodeList que no tiene las mismas características que una matriz. Use un bucle for en su lugar
color_btns = document.querySelectorAll(''#color > p'');
for (var i = 0; i < color_btns.length; i++) {
color_btns[i].onclick = function () {
for (var j = 0; j < color_btns.length; j++) {
if(color_btns[j].classList.contains(''selected'')) {
color_btns[j].classList.remove(''selected'');
}
}
color_btns[i].classList.add(''selected'');
document.querySelector(''#f_color'').value = color_btns[i].dataset.id;
};
}