События

Для взаимодействия с пользователем в JavaScript определен механизм событий. Например, когда пользователь нажимает кнопку, то возникает событие нажатия кнопки. В коде JavaScript мы можем определить возникновение события и как-то его обработать.

В JavaScript есть следующие типы событий:

  • События мыши (перемещение курсора, нажатие мыши и т.д.)
  • События клавиатуры (нажатие или отпускание клавиши клавиатуры)
  • События жизненного цикла элементов (например, событие загрузки веб-станицы)
  • События элементов форм (нажатие кнопки на форме, выбор элемента в выпадающем списке и т.д.)
  • События, возникающие при изменении элементов DOM
  • События, возникающие при касании на сенсорных экранах
  • События, возникающие при возникновении ошибок

Рассмотрим простейшую обработку событий. Например, на веб-странице у нас есть следующий элемент div:

<div id="rect" onclick="alert('Нажато')" style="width:50px; height:50px; background-color:blue;"></div>

Здесь определен обычный блок div, который имеет атрибут onclick, который задает обработчик события нажатия на блок div. То есть, чтобы обработать какое-либо событие, нам надо определить для него обработчик.

Также можно было бы вынести все действия по обработке события в отдельную функцию:

<div id="rect" onclick="displayMessage()" style="width:50px; height:50px; background-color:blue;"></div>
function displayMessage() {
    alert('Нажато');
}

Теперь обработчиком события будет выступать функция displayMessage.

- Передача параметров в обработчик события

В обработчик можно передавать параметры. Например, мы можем передать текущий объект, на котором возникает событие:

<a href="page1.html" onclick="return handler(this)">Страница 1</a>
function handler(obj) {
    alert(obj.href);
    return false;
}

Ключевое слово this указывает на текущий объект ссылки, на которую производится нажатие. И в коде обработчика мы можем получить этот объект и обратиться к его свойствам, например, к свойству href.

Кроме того, надо отметить, что здесь обработчик возвращает результат. Хотя в первом примере с блоком div от обработчика не требовалось возвращения результата. Дело в том, что для некоторых обработчиков можно подтвердить или остановить обработку события. Например, нажатие на ссылку должно привести к переадресации. Но возвращая из обработчика false, мы можем остановить стандартный путь обработки события, и переадресации не будет. Если же возвращать значение true, то событие обрабатывается в стандартном порядке.

Кроме непосредственно элемента-источника события в обработчик мы можем передавать объект event. Этот объект не определяется разработчиком, это просто аргумент функции обработчика, который хранит всю информацию о событии. Например:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<style>
			#rect {
				width:50px;
				height:50px;
				background-color:blue;
			}
		</style>
	</head>
	<body>
		<div id="rect" onclick="handler(event)"></div>
		
		<script>
			function handler(e) {
				alert(e.type); // получаем тип события - click
			}
		</script>
	</body>
</html>

В данном случае с помощью свойства type объекта event получаем тип события (в данном случае тип click).


Обработчики событий

- Встроенные обработчики

Встроенные обработчики (inline event handler) определяются в коде элемента с помощью атрибутов:

<div id="rect" onclick="handler(event)"></div>

Хотя этот подход прекрасно работает, но он имеет кучу недостатков:

  • Код HTML смешивается с кодом JavaScript, в связи с чем становится труднее разрабатывать, отлаживать и поддерживать приложение
  • Обработчики событий можно задать только для уже созданных на веб-странице элементов. Динамически создаваемые элементы в этом случае лишаются возможности обработки событий
  • К элементу для одного события может быть прикреплен только один обработчик
  • Нельзя удалить обработчик без изменения кода

- Свойства обработчиков событий

Проблемы, которые возникают при использовании встроенных обработчиков, были призваны решить свойства обработчиков. Подобно тому, как у html-элементов есть атрибуты для обработчиков, так и в коде JavaScript у элементов DOM мы можем получить свойства обработчиков, которые соответствуют атрибутам:

function handler(e) {
    alert(e.type);
}

document.getElementById("rect").onclick = handler;

В итоге нам достаточно взять свойство onclick и присвоить ему функцию, используемую в качестве обработчика. За счет этого код HTML отделяется от кода JavaScript. Стоит также отметить, что в обработчик события браузер автоматически передает объект Event, хранящий всю информацию о событии.

- Слушатели событий

Несмотря на то, что свойства обработчиков решают ряд проблем, которые связаны с использованием атрибутов, в то же время это также не оптимальный подход. Еще один способ установки обработчиков событий представляет использование слушателей.

Для работы со слушателями событий в JavaScript есть объект EventTarget, который определяет методы addEventListener() (для добавления слушателя) и removeEventListener() для удаления слушателя. И поскольку html-элементы DOM тоже являются объектами EventTarget, то они также имеют эти методы. Фактически слушатели представляют те же функции обработчиков.

Метод addEventListener() принимает два параметра: название события без префикса on и функцию обработчика этого события. Например:

var rect = document.getElementById("rect");

rect.addEventListener("click", function (e) {
    alert(e.type);
});

То есть в данном случае опять же обрабатывается событие click. И также можно было бы в качестве второго параметра передать название функции.

Удаление слушателя аналогично добавлению:

rect.removeEventListener("click", handler);

Преимуществом использования слушателей является и то, что мы можем установить для одного события несколько функций.


Объект event

При обработке события браузер автоматически передает в функцию обработчика в качестве параметра объект Event, который инкапсулирует всю информацию о событии. И с помощью его свойств мы можем получить эту информацию:

  • bubbles: возвращает true, если событие является восходящим. Например, если событие возникло на вложенном элементе, то оно может быть обработано на родительском элементе
  • cancelable: возвращает true, если можно отменить стандартную обработку события
  • currentTarget: определяет элемент, к которому прикреплен обработчик события
  • defaultPrevented: возвращает true, если был вызван у объекта Event метод preventDefault()
  • eventPhase: определяет стадию обработки события
  • target: указывает на элемент, на котором было вызвано событие
  • timeStamp: хранит время возникновения события
  • type: указывает на имя события

- Остановка выполнения события

С помощью метода preventDefault() объекта Event мы можем остановить дальнейшее выполнение события. В ряде случаев этот метод не играет большой роли. Однако в некоторых ситуациях он может быть полезен. Например, при нажатии на ссылку мы можем с помощью дополнительной обработки определить, надо ли переходить по ссылке или надо запретить переход. Или другой пример: пользователь отправляет данные формы, но в ходе обработки в обработчике события мы определили, что поля формы заполнены неправильно, и в этом случае мы также можем запретить отправку.

Например, запретим переход по ссылке после 12 часов:

function linkHandler(e) {
    var date = new Date();
    var hour = date.getHours();

    if(hour > 12) {
        e.preventDefault();
        document.write("После 12 переход запрещен");
    }
}

var link = document.getElementById("link");
link.addEventListener("click", linkHandler);

Распространение событий

Когда мы нажимаем на какой-либо элемент на станице и генерируется событие нажатия, то это событие может распространяться от элемента к элементу. Например, если мы нажимаем на блок div, то также мы нажимаем и на элемент body, в котором блок div находится. То есть происходит распространение события.

Есть несколько форм распространения событий:

  • Восходящие: событие распространяется вверх по дереву DOM от дочерних узлов к родительским
  • Нисходящие: событие распространяется вниз по дереву DOM от родительских узлов к дочерним, пока не достигнет того элемента, на котором это событие и возникло

- Восходящие события

Рассмотрим восходящие (bubbling) события, которые распространяются в верх по дереву DOM. Допустим, у нас есть следующая веб-страница:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<style>
			#blueRect {
				width:100px;
				height:100px;
				background-color:blue;
			}
			#redRect {
				width:50px;
				height:50px;
				background-color:red;
			}
		</style>
	</head>
	<body>
		<div id="blueRect">
			<div id="redRect"></div>
		</div>
		
		<script>
			var redRect = document.getElementById("redRect");
			redRect.addEventListener("click", function(){
				console.log("Событие на redRect");
			});
			 
			var blueRect = document.getElementById("blueRect");
			blueRect.addEventListener("click", function(){
				console.log("Событие на blueRect");
			});
			 
			document.body.addEventListener("click", function(){
				console.log("Событие на body");
			});
		</script>
	</body>
</html>

Если мы нажмем на вложенный div, то событие пойдет к родительскому элементу div и далее к элементу body:

Событие на redRect
Событие на blueRect
Событие на body

Надо сказать, что подобное поведение не всегда является желательным. И в этом случае мы можем остановить распространение события с помощью метода stopPropagation() объекта Event:

var redRect = document.getElementById("redRect");
redRect.addEventListener("click", function(e) {
    console.log("Событие на redRect");
    e.stopPropagation();
});

И в результате нажатия событие будет обработано только обработчиком для redRect.

- Нисходящие события

События также могут быть нисходящими (capturing). Для их использования в метод addEventListener() в качестве третьего необязательного параметра передается логическое значение true или false, которое указывает, будет ли событие нисходящим. По умолчанию все события восходящие.

Возьмем ту же веб-станицу, только изменим ее код JavaScript:

var redRect = document.getElementById("redRect");
redRect.addEventListener("click", function() {
    console.log("Событие на redRect");
}, true);
 
var blueRect = document.getElementById("blueRect");
blueRect.addEventListener("click", function() {
    console.log("Событие на blueRect");
}, true);
 
document.body.addEventListener("click", function() {
    console.log("Событие на body");
}, true);

Теперь события будут распространяться в обратном порядке:

Событие на body
Событие на blueRect
Событие на redRect

События мыши

Одну из наиболее часто используемых событий составляют события мыши:

  • click: возникает при нажатии указателем мыши на элемент
  • mousedown: возникает при нахождении указателя мыши на элементе, когда кнопка мыши находится в нажатом состоянии
  • mouseup: возникает при нахождении указателя мыши на элементе во время отпускания кнопки мыши
  • mouseover: возникает при вхождении указателя мыши в границы элемента
  • mousemove: возникает при прохождении указателя мыши над элементом
  • mouseout: возникает, когда указатель мыши выходит за пределы элемента

Например, обработаем события mouseover и mouseout:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<style>
			#blueRect {
				width:100px;
				height:100px;
				background-color:blue;
			}
		</style>
	</head>
	<body>
		<div id="blueRect"></div>
		
		<script>
			function setColor(e) {
				if(e.type === "mouseover") {
					e.target.style.backgroundColor = "red";
				} else if(e.type === "mouseout") {
					e.target.style.backgroundColor = "blue";
				}
			}

			var blueRect = document.getElementById("blueRect");
			blueRect.addEventListener("mouseover", setColor);
			blueRect.addEventListener("mouseout", setColor);
		</script>
	</body>
</html>

Теперь при наведении указателя мыши на блок blueRect он будет окрашиваться в красный цвет, а при уходе указателя мыши - блок будет обратно окрашиваться в синий цвет.

Объект Event является общим для всех событий. Однако для разных типов событий существуют также свои объекты событий, которые добавляют ряд своих свойств. Так, для работы с событиями указателя мыши определен объект MouseEvent, который добавляет следующие свойства:

  • altKey: возвращает true, если была нажата клавиша Alt во время генерации события
  • button: указывает, какая кнопка мыши была нажата
  • clientX: определяет координату Х окна браузера, на которой находился указатель мыши во время генерации события
  • clientY: определяет координату Y окна браузера, на которой находился указатель мыши во время генерации события
  • ctrlKey: возвращает true, если была нажата клавиша Ctrl во время генерации события
  • metaKey: возвращает true, если была нажата во время генерации события метаклавиша клавиатуры
  • relatedTarget: определяет вторичный источник возникновения события
  • screenX: определяет координату Х относительно верхнего левого угла экрана монитора, на которой находился указатель мыши во время генерации события
  • screenY: определяет координату Y относительно верхнего левого угла экрана монитора, на которой находился указатель мыши во время генерации события
  • shiftKey: возвращает true, если была нажата клавиша Shift во время генерации события

Определим координаты клика:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<style>
			#blueRect {
				width:100px;
				height:100px;
				background-color:blue;
			}
		</style>
	</head>
	<body>
		<div id="blueRect"></div>
		
		<script>
			function handleClick(e) {
				console.log("screenX: " + e.screenX);
				console.log("screenY: " + e.screenY);
				console.log("clientX: " + e.clientX);
				console.log("clientY: " + e.clientY);
			}
			
			var blueRect = document.getElementById("blueRect");
			blueRect.addEventListener("click", handleClick);
		</script>
	</body>
</html>

События клавиатуры

Другим распространенным типом событий являются события клавиатуры:

  • keydown: возникает при нажатии клавиши клавиатуры и длится, пока нажата клавиша
  • keyup: возникает при отпускании клавиши клавиатуры
  • keypress: возникает при нажатии клавиши клавиатуры, но после события keydown и до события keyup. Надо учитывать, что данное событие генерируется только для тех клавиш, которые формируют вывод в виде символов, например, при печати символов. Нажатия на остальные клавиши, например, на Alt, не учитываются

Для работы с событиями клавиатуры определен объект KeyboardEvent, который добавляет к свойствам объекта Event ряд специфичных для клавиатуры свойств:

  • altKey: возвращает true, если была нажата клавиша Alt во время генерации события
  • charCode: возвращает символ Unicode для нажатой клавиши (используется для события keypress)
  • keyCode: возвращает числовое представление нажатой клавиши клавиатуры
  • ctrlKey: возвращает true, если была нажата клавиша Ctrl во время генерации события
  • metaKey: возвращает true, если была нажата во время генерации события метаклавиша клавиатуры
  • shiftKey: возвращает true, если была нажата клавиша Shift во время генерации события

Например, мы можем с помощью клавиш клавиатуры перемещать элемент на веб-странице:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<style>
			html, body {
				margin:0;
				overflow:hidden;
			}
			#blueRect {
				width:100px;
				height:100px;
				background-color:blue;
			}
		</style>
	</head>
	<body>
		<div id="blueRect"></div>
		
		<script>
			function moveRect(e) {
				var blueRect = document.getElementById("blueRect");
				var cs = window.getComputedStyle(blueRect);
				var left = parseInt(cs.marginLeft);
				var top = parseInt(cs.marginTop);
				
				switch(e.keyCode) {
					case 37:  // если нажата клавиша влево
						if(left>0)
							blueRect.style.marginLeft = left - 10 + "px";
						break;
					case 38:   // если нажата клавиша вверх
						if(top>0)
							blueRect.style.marginTop = top - 10 + "px";
						break;
					case 39:   // если нажата клавиша вправо
						if(left < document.documentElement.clientWidth - 100)
							blueRect.style.marginLeft = left + 10 + "px";
						break;
					case 40:   // если нажата клавиша вниз
						if(top < document.documentElement.clientHeight - 100)
							blueRect.style.marginTop = top + 10 + "px";
						break;
				}
			}
			
			addEventListener("keydown", moveRect);
		</script>
	</body>
</html>

В данном случае обрабатывается событие keydown. В обработчике moveRect с помощью метода window.getComputedStyle() получаем стиль элемента blueRect. А затем из этого стиля выбираем значения свойств marginLeft и marginTop.

Здесь нас интересуют четыре клавиши: вверх, вниз, влево, вправо. Если одна из них нажата, производим действия: увеличение или уменьшение отступа элемента от верхней или левой границы. Ну и чтобы элемент не выходил за границы окна, проверяем предельные значения с помощью document.documentElement.clientWidth (ширина корневого элемента) и document.documentElement.clientHeight (высота корневого элемента).


Формы и их элементы

Один из способов взаимодействия с пользователями представляют html-формы. Например, если нам надо получить от пользователя некоторую информацию, мы можем определить на веб-странице формы, которая будет содержать текстовые поля для ввода информации и кнопку для отправки. И после ввода данных мы можем обработать введенную информацию.

Для создания формы используется элемент <form>:

<form name="search"></form>

В JavaScript форма представлена объектом HtmlFormElement. И после создания формы мы можем к ней обратиться различными способами.

Первый способ заключается в прямом обращении по имени формы:

var searchForm = document.search;

Второй способ состоит в обращении к коллекции форм документа и поиске в ней нужной формы:

var searchForm;

for (var i = 0; i < document.forms.length; i++) {
    if(document.forms[i].name === "search") {
		searchForm = document.forms[i];
	}
}

document.write(searchForm.name);

С помощью свойства name объекта формы мы можем получить значение атрибута name у соответствующего элемента формы в коде HTML.

Еще один способ сочетает оба подхода:

var searchForm = document.forms["search"];

И также можно применять стандартные способы для поиска элемента формы, например, по id, по тегу или по селектору. Например:

var searchForm = document.getElementsByTagname("form")[0];

Форма имеет ряд свойств, из которых наиболее важными являются вышерассмотренное свойство name, а также свойство elements, которое содержит коллекцию элементов формы.

Среди методов формы надо отметить метод submit(), который отправляет данные формы на сервер, и метод reset(), который очищает поля формы:

var searchForm = document.forms["search"];
searchForm.submit();
searchForm.reset();

Кнопки

Для отправки введенных данных на форме используются кнопки. Для создания кнопки используется либо элемент button:

<button name="send">Отправить</button>

Либо элемент input:

<input type="submit" name="send" value="Отправить" />

С точки зрения функциональности в HTML эти элементы не совсем равноценны, но в данном случае они нас интересуют с точки зрения взаимодействия с кодом JavaScript.

При нажатии на любой из этих двух вариантов кнопки происходит отправка формы по адресу, который указан у формы в атрибуте action, либо по адресу веб-страницы, если атрибут action не указан. Однако в коде JavaScript мы можем перехватить отправку, обрабатывая событие click:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
	</head>
	<body>
		<form name="search">
			<input type="text" name="key" />
			<input type="submit" name="send" value="Отправить" />
		</form>
		<script>
		function sendForm(e) {
			var keyBox = document.search.key;
			var val = keyBox.value;
			
			if(val.length>5) {
				alert("Недопустимая длина строки");
				e.preventDefault();
			} else {
				alert("Отправка разрешена");
			}
		}
		
		var sendButton = document.search.send;
		sendButton.addEventListener("click", sendForm);
		</script>
	</body>
</html>

При нажатии на кнопку происходит событие click, и для его обработки к кнопке прикрепляем обработчик sendForm. В этом обработчике проверяем введенный в текстовое поле текст. Если его длина больше 5 символов, то выводим сообщение о недопустимой длине и прерываем обычный ход события с помощью вызова e.preventDefault(). В итоге форма не отправляется. Если же длина текста меньше шести символов, то также выводится сообщение, и затем форма отправляется.


Текстовые поля

Для ввода простейшей текстовой информации предназначен элемент input:

<input type="text" name="key" size="10" maxlength="15" value="hello world" />

Данный элемент поддерживает ряд событий, в частности:

  • focus: происходит при получении фокуса
  • blur: происходит при потере фокуса
  • change: происходит при изменении значения поля
  • select: происходит при выделении текста в текстовом поле
  • keydown: происходит при нажатии клавиши клавиатуры
  • keypress: происходит при нажатии клавиши клавиатуры для печатаемых символов
  • keyup: происходит при отпускании ранее нажатой клавиши клавиатуры

Применим ряд событий:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
	</head>
	<body>
		<form name="search">
			<input type="text" name="key" placeholder="Введите ключ"></input>
			<input type="button" name="print" value="Печать" />
		</form>
		<div id="printBlock"></div>
		
		<script>
			var keyBox = document.search.key;
			
			// обработчик изменения текста
			function onchange(e) {
				// получаем элемент printBlock
				var printBlock = document.getElementById("printBlock");
				// получаем новое значение
				var val = e.target.value;
				// установка значения
				printBlock.textContent = val;
			}
			
			// обработка потери фокуса
			function onblur(e) {
				// получаем его значение и обрезаем все пробелы
				var text = keyBox.value.trim();
				if(text==="")
					keyBox.style.borderColor = "red";
				else
					keyBox.style.borderColor = "green";
			}
			
			// получение фокуса
			function onfocus(e){
				 
				// установка цвета границ поля
				keyBox.style.borderColor = "blue";
			}
			
			keyBox.addEventListener("change", onchange);
			keyBox.addEventListener("blur", onblur);
			keyBox.addEventListener("focus", onfocus);
		</script>
	</body>
</html>

Здесь к текстовому полю прикрепляется три обработчика для событий blur, focus и change. Обработка события change позволяет сформировать что-то вроде привязки: при изменении текста весь текст отображается в блоке printBlock. Но надо учитывать, что событие change возникает не сразу после изменения текста, а после потери им фокуса. Обработка события потери фокуса blur позволяет провести валидацию введенного значения. Например, в данном случае если текст состоит из пробелов или не был введен, то окрашиваем границу поля в красный цвет.

- Элемент textarea

Для создания многострочных текстовых полей используется элемент textarea:

<textarea rows="15" cols="40" name="textArea"></textarea>

Данный элемент генерирует все те же самые события, что и обычное текстовое поле:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
	</head>
	<body>
		<form name="search">
			<textarea rows="7" cols="40" name="message"></textarea>
		</form>
		<div id="printBlock"></div>
		
		<script>
			var messageBox = document.search.message;
			
			// обработчик ввода символа
			function onkeypress(e){
				// получаем элемент printBlock
				var printBlock = document.getElementById("printBlock");
				// получаем введенный символ
				var val = String.fromCharCode(e.keyCode);
				// добавление символа
				printBlock.textContent += val;
			}
			 
			function onkeydown(e){
				if(e.keyCode===8){ // если нажат Backspace
				 
					// получаем элемент printBlock
					var printBlock = document.getElementById("printBlock"), 
						length = printBlock.textContent.length;
					// обрезаем строку по последнему символу
					printBlock.textContent = printBlock.textContent.substring(0, length-1);
				}
			}
			 
			messageBox.addEventListener("keypress", onkeypress);
			messageBox.addEventListener("keydown", onkeydown);
		</script>
	</body>
</html>

Здесь к текстовому полю прикрепляются обработчики для событий keypress и keydown.

В обработчике keypress получаем введенный символ с помощью конвертации числового кода клавиши в строку:

var val = String.fromCharCode(e.keyCode);

Затем символ добавляется к содержимому блока printBlock.


Флажки и переключатели

Флажки представляют поле, в которое можно поставить отметки и которое создается с помощью элемента <input type="checkbox". Отличительную особенность флажка составляет свойство checked, которое в отмеченном состоянии принимает значение true:

<form name="myForm">
    <input type="checkbox" name="enabled" checked><span>Включить</span>
</form>

<div id="printBlock"></div>
var enabledBox = document.myForm.enabled;
 
function onclick(e) {
    var printBlock = document.getElementById("printBlock");
    var enabled = e.target.checked;
    printBlock.textContent = enabled;
}
 
enabledBox.addEventListener("click", onclick);

Нажатие на флажок генерирует событие click. В данном случае при обработке данного события мы просто выводим информацию, отмечен ли данный флажок, в блок div.

Переключатели представляют группы кнопок, из которых мы можем выбрать только одну. Переключатели создаются элементом <input type="radio".

Выбор или нажатие на одну из них также представляет событие click:

<form name="myForm">
    <input type="radio" name="languages" checked="checked" value="Java" /><span>Java</span>
    <input type="radio" name="languages" value="C#" /><span>C#</span>
    <input type="radio" name="languages" value="C++" /><span>C++</span>
</form>

<div id="printBlock"></div>
function onclick(e) {
    var printBlock = document.getElementById("printBlock");
    var language = e.target.value;
    printBlock.textContent = "Вы выбрали: " + language;
}

for (var i = 0; i < myForm.languages.length; i++) {
    myForm.languages[i].addEventListener("click", onclick);
}

При создании группы переключателей их атрибут name должен иметь одно и то же значение. В данном случае это - languages. То есть переключатели образуют группу languages. Поскольку переключателей может быть много, то при прикреплении к ним обработчика события нам надо пробежаться по всему массиву переключателей, который можно получить по имени группы.


Список select

Для создания списка используется html-элемент select. Причем с его помощью можно создавать как выпадающие списки, так и обычные с ординарным или множественным выбором. Например, стандартный список:

<select name="language" size="4">
    <option value="JS" selected="selected">JavaScript</option>
    <option value="Java">Java</option>
    <option value="C#">C#</option>
    <option value="C++">C++</option>
</select>

Атрибут size позволяет установить, сколько элементов будут отображаться одномоментно в списке. Значение size="1" отображает только один элемент списка, а сам список становится выпадающим. Если установить у элемента select атрибут multiple, то в списке можно выбрать сразу несколько значений.

Каждый элемент списка представлен html-элементом option, у которого есть отображаемая метка и есть значения в виде атрибута value.

В JavaScript элементу select соответствует объект HTMLSelectElement, а элементу option - объект HtmlOptionElement или просто Option.

Все элементы списка в JavaScript доступны через коллекцию options. А каждый объект HtmlOptionElement имеет свойства: index (индекс в коллекции options), text (отображаемый текст) и value (значение элемента). Например, получим первый элемент списка и выведем о нем через его свойства всю информацию:

<form name="myForm">
    <select name="language" size="4">
        <option value="JS" selected="selected">JavaScript</option>
        <option value="Java">Java</option>
        <option value="CS">C#</option>
        <option value="CPP">C++</option>
    </select>
</form>
var firstLanguage = myForm.language.options[0];
document.write("Index: " + firstLanguage.index + "<br/>");
document.write("Text: " + firstLanguage.text + "<br/>");
document.write("Value: " + firstLanguage.value + "<br/>");

В JavaScript мы можем не только получать элементы, но и динамически управлять списком. Например, применим добавление и удаление объектов списка:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
	</head>
	<body>
		<form name="myForm">
			<select name="language" size="5">
				<option value="JS" selected="selected">JavaScript</option>
				<option value="Java">Java</option>
				<option value="CS">C#</option>
				<option value="CPP">C++</option>
			</select>
			<p><input type="text" name="textInput" placeholder="Введите текст" /></p>
			<p><input type="text" name="valueInput" placeholder="Введите значение" /></p>
			<p><input type="button" name="addButton" value="Добавить" /><input type="button" name="removeButton" value="Удалить" /></p>
		</form>
		
		<script>
			var addButton = myForm.addButton, 
				removeButton = myForm.removeButton, 
				languagesSelect = myForm.language;
			
			// обработчик добавления элемента
			function addOption() {
				// получаем текст для элемента
				var text = myForm.textInput.value;
				// получаем значение для элемента
				var value = myForm.valueInput.value;
				// создаем новый элемента
				var newOption = new Option(text, value);
				languagesSelect.options[languagesSelect.options.length]=newOption;
			}
			
			// обработчик удаления элемент
			function removeOption() {
				var selectedIndex = languagesSelect.options.selectedIndex;
				// удаляем элемент 
				languagesSelect.options[selectedIndex] = null;
			}
			
			addButton.addEventListener("click", addOption);
			removeButton.addEventListener("click", removeOption);
		</script>
	</body>
</html>

Для добавления на форме предназначены два текстовых поля (для текстовой метки и значения элемента option) и кнопка. Для удаления выделенного элемента предназначена еще одна кнопка. За добавление в коде JavaScript отвечает функция addOption, в которой получаем введенные в текстовые поля значения, создаем новый объект Option и добавляем его в массив options объекта списка. За удаление отвечает функция removeOption, в которой просто получаем индекс выделенного элемента с помощью свойства selectedIndex и в коллекции options приравниваем по этому индексу значение null.

Для добавления/удаления также в качестве альтернативы можно использовать методы элемента select:

languagesSelect.add(newOption);
languagesSelect.remove(selectedIndex);

- События элемента select

Элемент select поддерживает три события: blur (потеря фокуса), focus (получение фокуса) и change (изменение выделенного элемента в списке). Рассмотрим применение события select:

<form name="myForm">
    <select name="language" size="5">
        <option value="JS" selected="selected">JavaScript</option>
        <option value="Java">Java</option>
        <option value="CS">C#</option>
        <option value="CPP">C++</option>
    </select>
</form>
<div id="selection"></div>
var languagesSelect = myForm.language;
 
function changeOption() {
    var selection = document.getElementById("selection");
    var selectedOption = languagesSelect.options[languagesSelect.selectedIndex];
    selection.textContent = "Вы выбрали: " + selectedOption.text;
}
 
languagesSelect.addEventListener("change", changeOption);

JSON

JSON (JavaScript Object Notation) представляет легковесный формат хранения данных. JSON описывает структуру и организацию данных JavaScript. Простота JSON привела к тому, что в настоящий момент он является наиболее популярным форматом передачи данных в среде web, вытеснив другой некогда популярный формат XML.

Объекты JSON очень похожи на объекты JavaScript, тем более что JSON является подмножеством JavaScript. В то же время важно их различать: JavaScript является языком программирования, а JSON является форматом данных.

JSON поддерживает три типа данных: примитивные значения, объекты и массивы. Примитивные значения представляют стандартные строки, числа, значение null, логические значения true и false.

Объекты представляют набор простейших данных, других объектов и массивов. Например, типичный объект JSON:

{
    "name": "Tom",
    "married": true,
    "age": 30
}

В JavaScript этому объекту соответствовал бы следующий:

var user = {
    name: "Tom",
    married: true,
    age: 30
}

Несмотря на общее сходство, в то же время есть и различия: в JSON названия свойств заключаются в кавычки, как обычные строки. Кроме того, объекты JSON не могут хранить функции, переменные, как объекты JavaScript.

Объекты могут быть сложными:

{
    "name": "Tom",
    "married": true,
    "age": 30,
    "company": {
        "name": "Microsoft",
        "address": "USA, Redmond"
    }
}

Массивы в JSON похожи на массивы JavaScript и также могут хранить простейшие данные или объекты:

["Tom", true, 30]

Массив объектов:

[{
    "name": "Tom",
    "married": true,
    "age": 30
},{
    "name": "Alice",
    "married": false,
    "age": 23
}]

- Сериализация в JSON и десериализация

Для сериализации объекта JavaScript в JSON применяется функция JSON.stringify():

var user = {
    name: "Tom",
    married: true,
    age: 30
};

var serializedUser = JSON.stringify(user);
document.write(serializedUser); // {"name":"Tom","married":true,"age":30}

Для обратной операции - десериализации или парсинга json-объекта в JavaScript применяется метод JSON.parse():

var user = {
    name: "Tom",
    married: true,
    age: 30
};

// сериализация
var serializedUser = JSON.stringify(user);

// десериализация
var tomUser = JSON.parse(serializedUser);
document.write(tomUser.name); // Tom