Основы программирования на JavaScript
Шрифт:
Ко всем потомкам элемента можно обратиться с помощью атрибута childNodes, который возвращает массив, содержащий все узлы потомки текущего элемента. Можно также использовать атрибуты firstChild и lastChild на любом элементе, чтобы получить ссылки на первый или на последний элемент.
Чтобы увидеть, как это работает, давайте напишем сценарий для раскраски чередующихся строк TR в таблице:
function setColors(tbody, color1, color2){
var colors = [color1, color2];
var counter = 0;
var tr = tbody.firstChild;
while(tr){
tr.style.backgroundColor = colors[counter++ % 2];
tr = tr.nextSibling;
}
}
Демонстрация
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Color #1: Color #2:
При рассмотрении этого небольшого фрагмента кода мало что нужно пояснять в том, как можно получить этот интересный небольшой эффект. Код начинается с получения ссылки на первый элемент TR в таблице с помощью метода firstChild. Затем каждый TR раскрашивается по очереди двумя разными цветами, используя tr.style. Цвет фона задается одним из двух цветов из массива colors. Если counter имеет четное значение, то цвет фона задается как color1. Иначе он задается как color2. Это реализуется с помощью оператора деления по модулю (%). Для тех, кто забыл, напомним, что операция вычисляет остаток при делении. 5/2 = 2 с остатком 1. Поэтому 5 % 2 (5 по модулю 2) = 1.
Здесь не будет обсуждаться в данный момент изменение стилей, но достаточно сказать, что element.style предоставляет доступ ко всему, что можно задать с помощью таблицы стилей. Если нужно, например, задать стиль элемента, то можно прочитать/записать весь стиль с помощью element.style.cssText.
После задания цвета фона берется следующий элемент TR в таблице. Это делается с помощью функции nextSibling, которая возвращает следующий элемент в DOM, с тем же предком, что и текущий элемент. Если посмотреть на тег TABLE, то все его потомки являются элементами TR, поэтому nextSibling будет в цикле перебирать все элементы TR. Если отыскивается элемент TR с потомками, состоящими из элементов TD, то nextSibling будет циклически перебирать все элементы TD. Когда элементов TR больше не останется, цикл автоматически закончится, так как TR будет неопределенным, что в JavaScript оценивается как false.
С целью рассмотрения оператора childNodes и функции getElementsByTagName перепишем приведенный пример немного по-другому:
function setColors(tbody, color1, color2){
var colors = [color1, color2];
for(var i=0; i<tbody.childNodes.length; i++){
tbody.childNodes[i].style.backgroundColor = colors[i % 2];
}
}
function setColors(tbody, color1, color2){
var colors = [color1, color2];
var trs = tbody.getElementsByTagName('TR');
for(var i=0; i<trs.length; i++){
trs[i].style.backgroundColor = colors[i % 2];
}
}
Обе эти функции делают то же самое, что и первая функция setColors, но написано это немного по-другому. Первая функция использует атрибут childNodes. Как ранее говорилось, childNodes содержит массив, элементами которого являются потомки. Поэтому мы циклически перебираем tbody.childNodes и изменяем цвет каждого потомка, которые все должны быть элементами TR.
Другая функция использует новую функцию getElementsByTagName, которая выдает массив всех элементов с указанным именем тега. Так как нам требуются все элементы TR, то мы просто передаем в функцию 'TR'
и получаем список всех элементов TR в таблице. После этого код почти идентичен предыдущей функции.Работа с текстом немного отличается от работы с другими элементами DOM. Первое: каждый фрагмент текста на странице помещен в невидимый узел #TEXT. Поэтому следующий код HTML
<div id="ourTest">this is <a href="#">a link</a> and an image: <img src="img.jpg"></div>
имеет четыре корневых элемента: текстовый узел со значением "this is ", элемент A, еще один текстовый узел со значением " and an image: " и, наконец, элемент IMG. Элемент A имеет конечный текстовый узел в качестве потомка со значением " a link ". Когда необходимо изменить текст, то прежде всего необходимо получить этот "невидимый" узел. Если мы хотим изменить текст " and an image: ", то необходимо написать:
document.getElementById('ourTest').childNodes[2].nodeValue = 'our new text';
document.getElementById('ourTest') дает нам тег div. childNodes[2] дает узел текста " and an image: " и наконец nodeValue изменяет значение этого узла текста.
Что, если требуется добавить к этому еще текст, но не в конце, а перед " a link "?
var newText = document.createTextNode('our new text');
var ourDiv = document.getElementById('ourTest');
ourDiv.insertBefore(newText, ourDiv.childNodes[1]);
Первая строка показывает, как создать текст с помощью document.createTextNode. Это аналогично функции использованной ранее функции document.createElement. Третья строка содержит еще одну новую функцию insertBefore, которая аналогична appendChild, за исключением того, что имеет два аргумента: добавляемый элемент и существующий элемент, перед которым надо сделать вставку. Так как мы хотим добавить новый текст перед элементом A и знаем, что элемент A является вторым элементом в div, то мы используем ourDiv.childNodes[1] в качестве второго аргумента для insertBefore.
По большей части это все манипуляции с DOM. Если требуется создать, например, поле с изменяемым размером, то для изменения ширины и высоты поля будут использоваться те же функции мыши и функции getAttribute и setAttribute. Очень похожим образом, если изменять верхнюю и левую позицию стиля элемента, то можно перемещать элементы по странице, либо в ответ на ввод мыши (перетаскивание), либо по таймеру (анимация).
В качестве последнего замечания к этой лекции: одним из наиболее полезных средств при попытке протестировать или отладить код JavaScript, который изменяет DOM, является сценарий обхода дерева DOM. Проще говоря - это сценарий, который показывает каждый элемент и каждый атрибут объекта DOM. Описание этого кода выходит за рамки этой лекции, но он мог бы, например, показывать все атрибуты и объекты-потомки любого получаемого в качестве аргумента объекта.
Теперь можно включить свое воображение и экспериментировать, так как почти нет ничего такого, чего нельзя сделать со страницей HTML, когда вы знаете, как обращаться с DOM. В следующей лекции будут рассмотрены объекты окна и документа.
Лекция 7. Объект документа и объект окна