Получить все элементы по ClassName и изменить ClassName
Я хотел бы...
- Сканировать документ для всех элементов, имеющих определенное имя класса
- Выполните некоторые ключевые функции в innerHTML этого элемента
- Измените имя класса для этого элемента, чтобы, если я сделаю другое сканирование позже, я не переделаю этот элемент
Я думал, что этот код будет работать, но по какой-то причине он прерывает цикл после первого экземпляра, а имена классов классов никогда не меняются. Без рамок пожалуйста.
function example()
{
var elementArray;
elementArray = document.getElementsByClassName("exampleClass");
for(var i = 0; i < elementArray.length; i++)
{
// PERFORM STUFF ON THE ELEMENT
elementArray[i].setAttribute("class", "exampleClassComplete");
alert(elementArray[i].className);
}
}
EDIT (FINAL ANSWER). Вот окончательный продукт и то, как я реализовал решение @cHao на своем сайте. Цель состояла в том, чтобы захватить ассортимент временных меток на странице и изменить их на время назад. Спасибо всем за вашу помощь, я узнал тонну от этого вопроса.
function setAllTimeAgos()
{
var timestampArray = document.getElementsByClassName("timeAgo");
for(var i = (timestampArray.length - 1); i >= 0; i--)
{
timestampArray[i].innerHTML = getTimeAgo(timestampArray[i].innerHTML);
timestampArray[i].className = "timeAgoComplete";
}
}
Ответы
Ответ 1
Проблема в том, что возвращаемый вам NodeList является "live" - он изменяется при изменении имени класса. То есть, когда вы меняете класс на первом элементе, список сразу на один элемент короче, чем он был.
Попробуйте следующее:
while (elementArray.length) {
elementArray[0].className = "exampleClassComplete";
}
(Нет необходимости использовать setAttribute()
для установки значения "class" - просто обновите свойство "className". Использование setAttribute()
в старых версиях IE не будет работать в любом случае.)
В качестве альтернативы, преобразуйте NodeList в простой массив, а затем используйте свою индексированную итерацию:
elementArray = [].slice.call(elementArray, 0);
for (var i = 0; i < elementArray.length; ++i)
elementArray[i].className = "whatever";
Как отмечено в комментарии, это имеет то преимущество, что не полагается на семантику объектов NodeList. (Отметьте также, еще раз спасибо комментарию, что если вам нужно, чтобы это работало в более старых версиях Internet Explorer, вам пришлось бы писать явный цикл для копирования ссылок на элементы из NodeList в массив.)
Ответ 2
Большинство функций DOM, которые возвращают список элементов, возвращают NodeList, а не массив. Самое большое различие заключается в том, что NodeList, как правило, жив, что означает, что изменение документа может привести к появлению или исчезновению узлов. Это может привести к тому, что узлы будут перемещаться немного, и сбросить цикл, который не учитывает его.
Вместо того, чтобы превращать список в массив или что-то еще, вы можете просто прокрутить назад в списке, который вы вернетесь.
function example()
{
var elements = document.getElementsByClassName("exampleClass");
for(var i = elements.length - 1; i >= 0; --i)
{
// PERFORM STUFF ON THE ELEMENT
elements[i].className = "exampleClassComplete";
// elements[i] no longer exists past this point, in most browsers
}
}
Жизнеспособность NodeList не будет иметь значения в тот момент, поскольку единственные элементы, удаленные из нее, будут теми, которые остались после того, который вы сейчас используете. Узлы, которые появляются перед ним, не будут затронуты.
Ответ 3
Другим подходом может быть использование селектора:
var arr = document.querySelectorAll('.exampleClass');
for (var i=0;i<arr.length;i++) {
arr.innerHTML = "new value";
}
Хотя он несовместим со старыми браузерами, он также может сделать трюк, если webcontent предназначен для современных браузеров.
Ответ 4
Вы также можете использовать 2 массива, вставлять данные в первый массив, а затем делать то, что вам нужно [как изменить класс элемента]:
function example()
{
var elementArray=[];
var elementsToBeChanged=[];
var i=0;
elementArray = document.getElementsByClassName("exampleClass");
for( i = 0; i < elementArray.length; i++){
elementsToBeChanged.push(elementArray[i]);
}
for( i=0; i< elementsToBeChanged.length; i++)
{
elementsToBeChanged[i].setAttribute("class", "exampleClassComplete");
}
}
Ответ 5
Другая возможность, которая также должна быть кросс-браузером, использует ручное taylored getElementsByClassName, которое возвращает фиксированный список node как массив. Это должно поддерживать IE5.5 и выше.
function getElementsByClassName(node, className) {
var array = [],
regex = new RegExp("(^| )" + className + "( |$)"),
elements = node.getElementsByTagName("*"),
length = elements.length,
i = 0,
element;
while (i < length) {
element = elements[i];
if (regex.test(element.className)) {
array.push(element);
}
i += 1;
}
return array;
}