Основы работы с DOM в JavaScript
Теория
В данном уроке мы разберем основы работы с событиями, атрибутами и getElementById на языке JavaScript.
Итак, для чего собственно JavaScript предназначен: для изменения элементов страницы и реакции на действия пользователя. Теперь скрипты более зрелищные и полезные.
Начнем мы с того, что научим код реагировать на действия пользователя сайта. Например, пользователь нажмет куда-либо мышкой, а код в ответ должен будет обработать это нажатие и вывести на экран какую-либо информацию.
Действия пользователя, которые можно отследить через JavaScript, называются событиями. События могут быть следующими: клик мышкой на элемент страницы, наведение мышкой на элемент страницы или наоборот - уход курсора мыши с элемента и т.д. Кроме того, есть события, не зависящие от действий пользователя, например, событие по загрузке страницы в браузер.
В JavaScript существует несколько способов работы с событиями. Начнем с самого простого из них.
Основы работы с событиями
Самый простой способ задать реакцию элемента на определенное событие - указать ее с помощью атрибута для определенного тега. К примеру, событию "нажатие мышкой" соответствует атрибут onclick, событию "наведение мышкой" - атрибут onmouseover, а событию "уход курсора с элемента" - атрибут onmouseout.
Значением атрибута с событием служит JavaScript-код. В следующем примере по нажатию мышкой на кнопку выполнится функция alert:
<input type=submit onclick=alert('!')>
А сейчас по клику на элемент выполнится функция func:
<input type=submit onclick=func()>
<script>function func(){alert('!')}</script>
Можно выполнить не 1 функцию, а несколько:
<input type=submit onclick=func1();func2()>
<script>function func1(){alert('1')}function func2(){alert('2')}
Обратите внимание на то, что, если внутри атрибута есть двойные кавычки (например, для строки), а внешние кавычки атрибута тоже двойные - onclick="alert("!")", то такой код работать не будет.
Способы исправления: смена внешних кавычек на одинарные onclick='alert("!")', экранирование внутренних кавычек обратным слешем onclick="alert(\"!\")" или же просто переносом JavaScript-кода из атрибута в функцию, а в атрибуте остается только имя функции onclick=func().
То же самое для одинарных: onclick='alert('!')'.
Таблица атрибутов для событий
Все возможные атрибуты смотрите в справочнике JavaScript.
Работа с getElementById
Сейчас получим элементы страницы и проведем с ними различные манипуляции (сменим текст, цвет и др.).
Пример 1
Пусть на странице есть тег с атрибутом id в значении t. Запишем ссылку на этот тег в переменную e. Для этого воспользуемся методом getElementById, который получает элемент по его id.
Эта запись произойдет по клику на кнопку, которой задается атрибут onclick. При нажатию на эту кнопку сработает функция f1, которая найдет на странице элемент с id равным t1 и запишет ссылку на него в переменную e1:
<input type=text id=t1>
<input type=submit onclick=f1()>
<script>function f1(){e1=document.getElementById('t1')}
Теперь в переменной e1 лежит ссылка на элемент с атрибутом id в значении t1. Сама переменная e1 является объектом.
Этот объект и тег страницы связаны друг с другом (можем поменять какие-либо свойства объекта e1 и при этом увидим изменения на странице, которые произойдут с полученным элементом).
Практика. Основы работы с атрибутами HTML через JavaScript
Пример 2
Считываем и изменяем атрибуты тегов. Пусть даны инпут с id равным t2 и кнопка, по клику на которую будет запускаться функция f2:
Внутри функции f2 получим инпут по его id и запишем ссылку на него в переменную e2:
<input type=text value=v2 id=t2>
<input type=submit onclick=f2()>
<script>function f2(){e2=document.getElementById('t2')}</script>
Пример 3
Выводится содержимое атрибутов инпута. Чтобы получить доступ к атрибуту value, следует написать e3.value, где e3 - это переменная, в которую с помощью getElementById записана ссылка на элемент, а value - это атрибут тега, который нас интересует.
Выводится содержимое атрибута: alert(e3.value) (или записывается в переменную):
<input type=text value=v3 id=t3>
<input type=submit onclick=f3()>
<script>function f3(){e3=document.getElementById('t3');alert(e3.value)}//выведет v3
</script>
Пример 4
Считывается значения и других атрибутов: e4.id - значение атрибута id, e4.type - значение атрибута type:
<input type=text value=v4 id=t4>
<input type=submit onclick=f4()>
<script>function f4(){e4=document.getElementById('t4');
alert(e4.value);//выведет v4
alert(e4.id);//выведет t4
alert(e4.type);//выведет text
}</script>
Пример 5
Можно не только считывать значения атрибутов, но и изменять их. Чтобы поменять значение атрибута value, нужно просто присвоить его конструкции e5.value:
<input type=text value=v5 id=t5>
<input type=submit onclick=f5()>
<script>function f5(){e5=document.getElementById('t5');e5.value='q5'}//присвоим новое значение атрибуту value
</script>
Пример 6
Ну, а теперь самое сложное: можно не вводить переменную e6, а строить цепочку из точек так:
<input type=text value=v6 id=t6>
<input type=submit onclick=f6()>
<script>function f6(){alert(document.getElementById('t6').value)}//выведет v6
</script>
Пример 7
Такой же цепочкой можно производить и перезапись атрибутов:
<input type=text value=v7 id=t7>
<input type=submit onclick=f7()>
<script>function f7(){document.getElementById('t7').value='q7'}</script>
Пример 8
В большинстве случаев введение переменной удобнее. Сравнить 2 примера (8 и 9):
Ввод переменной e8 и можно считывать любое количество атрибутов, при этом getElementById вызывается только 1 раз:
<input type=text value=v8 id=t8>
<input type=submit onclick=f8()>
<script>function f8(){e8=document.getElementById('t8');e8.value='q8';e8.type='submit'}</script>
Пример 9
А тут новая переменная не вводится и поэтому приходится вызывать getElementById 2 раза:
<input type=text value=v9 id=t9>
<input type=submit onclick=f9()>
<script>function f9(){document.getElementById('t9').value='q9';document.getElementById('t9').type='submit'}</script>
Этот код стал сложнее, но компактнее. Кроме того, если надо сменить значение id с t9 на w9, это придется делать во многих местах (неудобно).
Еще проблема - нагрузка на браузер. Поиск элементов по странице, который делает метод getElementById, - это медленная операция (любая работа с элементами страницы - это медленная операция). Если каждый раз используется getElementById, то браузер каждый раз будет обрабатывать страницу и искать элемент с заданным id несколько раз (не важно, что id одинаковые), совершая бесполезные операции, которые замедляют работу браузера. Если используется переменная e8, то никакого поиска по странице не происходит (элемент уже найден и ссылка на него лежит в переменной e8). Исключения: атрибуты class и for.
Пример 10
При работе с атрибутами существует исключение - это атрибут class.
Слово class является специальным в JavaScript и поэтому нельзя просто написать e10.class, вместо этого надо писать e10.className.
На экран выводится значение атрибута class:
<input type=text class='aa b' id=t10>
<input type=submit onclick=f10()>
<script>function f10(){e10=document.getElementById('t10');alert(e10.className)}</script>
Есть и другие атрибуты, которые называются иначе, чем свойство. Например, атрибуту for (<label for='…'>) соответствует свойство с названием htmlFor.
Работа с this
Специальный объект this, который указывает на текущий элемент (элемент в котором произошло событие). Причем указывает так, будто этот элемент уже получен методом getElementById.
Как работать с this и в чем удобство такого подхода.
Есть задача по нажатию на инпут вывести на экран содержимое его value.
Пока умеем только так:
Пример 11
<input type=submit onclick=f11() id=t11 value=v11>
<script>function f11(){e11=document.getElementById('t11');alert(e11.value)}</script>
В принципе, решение хорошее, но представим теперь, что есть много инпутов и по нажатию на каждый нужно выводить его value.
В этом случае получится так:
<input type=submit onclick=f11a() id=t11a value=v11a>
<input type=submit onclick=f11b() id=t11b value=v11b>
<input type=submit onclick=f11c() id=t11c value=v11c>
<script>
function f11a(){e11=document.getElementById('t11a');alert(e11.value)}
function f11b(){e11=document.getElementById('t11b');alert(e11.value)}
function f11c(){e11=document.getElementById('t11c');alert(e11.value)}
</script>
Виден недостаток подхода: для каждого инпута приходится создавать свою функцию обработки клика (и делают эти функции практически 1 и тоже).
Если будет 10 инпутов, то придется сделать 10 функций (неудобно).
Пример 12
Упростим задачу: будем передавать параметром функции id текущего элемента. И вместо большого количества функций все сведется к 1 функции:
<input type=submit onclick=f12('t12a') id=t12a value=v12a>
<input type=submit onclick=f12('t12b') id=t12b value=v12b>
<input type=submit onclick=f12('t12c') id=t12c value=v12c>
<script>function f12(id){e12=document.getElementById(id);alert(e12.value)}</script>
Все-равно есть недостаток: каждому элементу придется вводить разные id.
Пример 13. Решения задачи через this
Сделаем так, что каждый инпут будет выводить свое содержимое по нажатию. Для этого параметром функции передадим объект this, вот так: f13(this).
this - это уже готовая ссылка на объект. Т.е., если я кликаю на 1-й инпут, в this окажется ссылка на него, если на 2-й инпут, то на него, и т.д.
this передается параметром функции и попадает в переменную e13. Этот e13 ведет себя так, будто получен таким образом: e13=document.getElementById(…), но получать его таким образом не надо, там уже все готово. К примеру, e13.value указывает на value инпута и т.д.
Самое просто решение:
<input type=submit onclick=f13(this) value=v13a>
<input type=submit onclick=f13(this) value=v13b>
<input type=submit onclick=f13(this) value=v13c>
<script>function f13(e13){alert(e13.value)}</script>
Основы работы с CSS
В JavaScript работа с CSS свойствами происходит путем изменения значения атрибута style для элемента.
Пример 14
Чтобы поменять цвет нужно построить следующую цепочку e14.style.color и присвоить ей нужное значение цвета:
<input type=text value=v14 id=t14>
<input type=submit onclick=f14()>
<script>function f14(){e14=document.getElementById('t14');e14.style.color='red'}</script>
Пример 15
Можно также и не вводить переменную e15, а построить очень длинную цепочку:
<input type=text value=v15 id=t15>
<input type=submit onclick=f15()>
<script>function f15(){document.getElementById('t15').style.color='red'}</script>
Пример 16
Существует свойства CSS, которые пишутся через дефис (font-size). В этом случае оно преобразуется в fontSize:
<input type=text value=v16 id=t16>
<input type=submit onclick=f16()>
<script>function f16(){e16=document.getElementById('t16');e16.style.fontSize='88px'}</script>
Пример 17
Работу с кроссбраузерными приставками рассмотрим на примере свойства -moz-box-sizing (оно преобразуется в mozBoxSizing), остальные свойства с приставками аналогичны:
<input type=text value=v17 id=t17>
<input type=submit onclick=f17()>
<script>function f17(){e17=document.getElementById('t17');e17.style.mozBoxSizing='border-box'}</script>
Пример 18
Внимание, свойство float является исключением (оно является специальным в JavaScript) и вместо него следует писать cssFloat:
<input type=text value=v18 id=t18>
<input type=submit onclick=f18()>
<script>function f18(){e18=document.getElementById('t18');e18.style.cssFloat='left'}</script>
Практика
Примеры решения задач
Задача 1. Алерт по нажатию на кнопку
Повторите поведение кнопки по нажатию на нее:
Решение:
<button onclick=alert('Привет')>Нажми</button>
Задача 2. Изменение текста в инпуте
Повторите поведение кнопки по нажатию на нее (она меняет текст в инпуте):
Решение:
<button onclick=e2buttonClick()>Нажми</button>
<input type=text id=e2input value=v2>
<script>function e2buttonClick(){input=document.getElementById('e2input');input.value='q2'}</script>
Задача 3. Вывод содержимого инпута
Повторите поведение кнопки по нажатию на нее (она выводит алертом содержимое инпута):
Решение:
<button onclick=e3buttonClick()>Нажми</button>
<input type=text id=e3input value=v3>
<script>function buttonClick(){input=document.getElementById('e3input');alert(input.value)}</script>
Задача 4. Квадрат содержимого инпута
Повторите поведение кнопки по нажатию на нее (она выводит алертом содержимое инпута, возведенное в квадрат):
Решение:
<input type=text id=e4input placeholder='Введите число'> <button onclick=e4buttonClick()>Нажми</button><script>function e4buttonClick(){input=document.getElementById('e4input');number=Number(input.value);square=number*number;alert(square)}</script>
Задача 5. Обмен содержимым между инпутами
Повторите поведение кнопки по нажатию на нее (она осуществляет обмен содержимым между двумя инпутами, можете понажимать на нее несколько раз или вручную сменить содержимое инпутов):
Решение:
<button onclick=e5buttonClick()>Нажми</button> <input type=text id=e5input1 value=!!!> <input type=text id=e5input2 value=???> <script>function e5buttonClick(){input1=document.getElementById('e5input1'); input2=document.getElementById('e5input2'); input1Value=input1.value; input2Value=input2.value;input1.value=input2Value; input2.value=input1Value}</script>
Задача 6. По нажатию на кнопку меняется ее текст
Повторите поведение кнопки по нажатию на нее (поменяется ее текст):
Решение:
<input type=button onclick=e6buttonClick(this) value=Нажми><script>function e6buttonClick(elem){elem.value='Новый текст кнопки'}</script>
Задача 7. Работа с CSS
Повторите поведение кнопки по нажатию на нее (она меняет цвет текста в инпуте):
Решение:
<button onclick=e7buttonClick()>Нажми</button> <input type=text id=e7input value=текст><script>function e7buttonClick(){input=document.getElementById('e7input');input.style.color='red'}</script>
Можно не вводить промежуточную переменную input, а сразу поменять цвет:
<script>function e7buttonClick(){document.getElementById('e7input').style.color='red'}</script>
Задача 8. Блокирование полей ввода
Повторите поведение кнопок по нажатию на них (1 из них блокирует инпут с помощью атрибута disabled, а другая разблокирует):
Решение:
<button onclick=e8button1Click()>Заблокировать</button>
<button onclick=e8button2Click()>Отблокировать</button>
<input type=text id=e8input value=текст>
//Заблокирует элемент
function button1Click(){input=document.getElementById('e8input');input.disabled=true}
//Отблокирует элемент
function button2Click(){input=document.getElementById('e8input');input.disabled=false}
Задачи для решения
События через атрибуты
…