Javascript заполнение формы. Формы и поля форм. Контактная форма в стиле старой печатной машинки

12.07.2019

Как и многие веб-разработчики, я посвящаю много времени тестированию пользовательского интерфейса сайтов, над которыми работаю.

Автоматизированное тестирование, конечно, является хорошей помощью в этом процессе, но «болевые точки » в интерфейсе зачастую невозможно выявить иным способом, кроме как использовать сайт. Ещё и ещё раз. Этот процесс может очень быстро надоедать. Особенно заполнение форм.

Я сам попал в такую ситуацию пару месяцев назад, когда мы добавляли британский фунт к поддерживаемым валютам при расчёте в Wufoo .

Для проверки необходимо было заполнить множество полей с именами, адресами, номерами кредиток и всего прочего, что подразумевается в процессе расчёта. Разумеется, значительная часть этих данных не должна была повторяться:

В конце концов, я сделал букмарклет для быстрого заполнения форм тестовыми данными. (Bookmarklet – программа на JavaScript , выполненная в виде закладки в браузере, гибрид английских слов «bookmark » – закладка и «applet » – маленькое приложение. – Прим. перев.)

Я выбрал форму букмарклета, потому что:

  • его легко передать пользователю;
  • его легко обновить без участия пользователя;
  • он запускается на любой платформе без изменений.

Вы можете легко сделать букмарклет, создав новый «загончик » на CodePen и поместив в HTML что-то вроде:

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

В этом проекте я полагался на jQuery для придания коду максимальной удобочитаемости и кроссбраузерности. Если кому-то нужна версия на чистом JavaScript , напишите мне комментарий – я постараюсь что-нибудь сообразить.

Для создания случайных данных я использовал замечательную библиотеку Faker . Её JavaScript -реализацию можно взять здесь .

Основа букмарклета

Мы можем поместить весь код прямо в ссылку. Но такой вариант будет неудобно читать и сопровождать. Кроме того, мне хотелось иметь возможность вносить исправления в код, не заставляя пользователей обновлять закладку. Так что лучше оставить в букмарклете ссылку на внешний файл.

Сам букмарклет выглядит так:

Мой букмарклет

В нём мы подгружаем скрипт в тело страницы и добавляем туда же ссылку на внешний файл JavaScript . Необходимо заметить, что, если букмарклет применяется к тестированию страницы, загружаемой по https , то и внешний JS -файл должен отдаваться по https , иначе браузер выдаст ошибку безопасности.

Вполне возможно, что при разработке букмарклета вы захотите воспользоваться локальным сервером. В таком случае не забудьте заменить адрес в ссылке на адрес реального сервера, когда будете распространять ваш скрипт.

Заполнение полей

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

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

Поэтому мы обернём его в самозапускающуюся анонимную функцию . Это соответствующим образом ограничит область видимости наших функций и переменных:

Мне очень нравится функция генератора псевдослучайных чисел, приведённая Крисом Койлером в этой статье . Воспользуемся ей по мере необходимости:

var _rand = function(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }

Теперь загрузим FakerJS . Поскольку наш скрипт зависит от jQuery , мы можем использовать его механизм отложенной загрузки при помощи функции $.getScript :

Теперь, когда доступ к Faker нам обещан , мы можем использовать его методы для генерации разнообразных правдоподобных имён, мест, адресов и других тестовых данных.

Повторное использование сгенерированных данных обеспечит нам следующий конструктор:

var FormData = function(faker) { this.faker = faker; this.randomWord = faker.Internet.domainWord(); this.username = "fake_" + this.randomWord; this.username += _rand(100,9999); // set this value to your password specifications this.password = "pass1234"; this.name = faker.Name.findName(); this.address1 = faker.Address.streetAddress(); this.city = faker.Address.city(); this.state = faker.random.br_state_abbr(); this.zip = faker.Address.zipCode(); // Chris" actual credit card number this.cc = "4242 4242 4242 4242"; this.exp1 = _rand(1,12); this.exp2 = _rand(14,22); this.cvv = _rand(100,999); };

Неплохо было бы протестировать также чекбоксы и радиокнопки на нашем сайте, выбирая их в случайном порядке. Для этого нам придётся несколько расширить функциональность нашего конструктора:

// Randomly select dropdown FormData.prototype.randomizeSelect = function(el) { var $el = $(el), len = $el.find("option").length - 1; $el.children("option") .prop("selected", false) .eq(_rand(1,len + 1)) .prop("selected", true); }; // Randomly select radio button FormData.prototype.randomizeRadio = function(radios) { radios.not(""); var len = radios.length; radios .prop("checked", false) .eq(_rand(0, len - 1)) .prop("checked", true); }; // Add some lorem text for textareas FormData.prototype.randomizeParagraph = function(el) { $(el).val(this.faker.Lorem.sentence(5)); }; // Randomize all checkbox fields FormData.prototype.randomizeCheckbox = function(el) { var $el = $(el); $el.prop("checked", false); if (_rand(0,1) === 0) { $el.prop("checked", true); } }; FormData.prototype.randomizeEmail = function(el) { // if we want different emails for all email fields, we can modify this $(el).val("chriscoyier+" + this.randomWord + "@gmail.com"); };

И наконец, нам нужно сопоставить генерируемые данные с различными полями тестируемых форм. Мы извлечём из нашей страницы все поля форм и заполним их данными в соответствии с их типом и CS S-классом.

В таком виде наш скрипт прекрасно реализует разделение между механизмом генерации данных и механизмом их использования:

var fillForm = function() { data = new FormData(window.Faker); $("#name").val(data.name); $("#username").val(data.username); $("#cc").val(data.cc); $("#exp-1").val(data.exp1); $("#exp-2").val(data.exp2); $("#cvv").val(data.cvv); $("#address").val(data.address1); $("#city").val(data.city); $("#state").val(data.state); $("#zip").val(data.zip); $("#pw").val(data.password); $("#pw-repeat").val(data.password); data.randomizeRadio($("")); // Randomize all select boxes $("select").each(function() { data.randomizeSelect(this); }); // Randomize all checkboxes $("input) found = true; } if (!found) ok = false; } return ok; } function test(input) { if (!check(input, "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "/", "-", " ")) { alert("Input not ok."); } else { alert("Input ok!"); } } // --> Telephone: Функция test() определяет, какие из введенных символов признаются корректными.

Предоставление информации, введенной в форму

Какие существуют возможности для передачи информации, внесенной в форму? Самый простой способ состоит в передаче данных формы по электронной почте (этот метод мы рассмотрим поподробнее).
Если Вы хотите, чтобы за вносимыми в форму данными следил сервер, то Вы должны использовать интерфейс CGI (Common Gateway Interface). Последнее позволяет Вам автоматически обрабатывать данные. Например, сервер мог бы создавать базу данных со сведениями, доступную для некоторых из клиентов. Другой пример - поисковые страницы, такие как Yahoo. Обычно в них представлена форма, позволяющая создавать запрос для поиска в собственной базе данных. В результате пользователь получает ответ вскоре после того, как нажимает на соответствующую кнопку. Ему не приходится ждать, пока люди, отвечающие за поддержание данного сервера, прочтут указанные им данные и отыщут требуемую информацию. Все это автоматически выполняет сам сервер. JavaScript не позволяет делать таких вещей.
С помощью JavaScript Вы не сможете создать книгу читательских отзывов, поскольку JavaScript лишен возможности записывать данные в какой-либо файл на сервере. Делать это Вы можете только через интерфейс CGI. Конечно, Вы можете создать книгу отзывов, для которой пользователи присылали сведения по электронной почте. Однако в этом случае Вы должны заносить отзывы вручную. Так можно делать, если Вы не предполагаете получать ежедневно по 1000 отзывов.
Соответствующий скрипт будет простым текстом HTML. И никакого программирования на JavaScript здесь вовсе не нужно! Конечно за исключением того случая, если Вам понадобится перед пересылкой проверить данные, занесенные в форму - и здесь уже Вам действительно понадобится JavaScript. Я должен лишь добавить, что команда mailto работает не повсюду - например, поддержка для ее отсутствует в Microsoft Internet Explorer 3.0.

Нравится ли Вам эта страница? Вовсе нет.
Напрасная трата времени.
Самый плохой сайт в Сети.
Параметр enctype="text/plain" используется для того, чтобы пересылать именно простой текст без каких-либо кодируемых частей. Это значительно упрощает чтение такой почты.

Если Вы хотите проверить форму прежде, чем она будет передана в сеть, то для этого можете воспользоваться программой обработки событий onSubmit. Вы должны поместить вызов этой программы в тэг . Например:

Function validate() { // check if input ok // ... if (inputOK) return true else return false; } ... ... Форма, составленная таким образом, не будет послана в Интернет, если в нее внесены некорректные данные.

Выделение определенного элемента формы

С помощью метода focus() Вы можете сделать вашу форму более дружественной. Так, Вы можете выбрать, который элемент будет выделен в первую очередь. Либо Вы можете приказать браузеру выделить ту форму, куда были введены неверные данные. То есть, что браузер сам установит курсор на указанный Вами элемент формы, так что пользователю не придется щелкать по форме, прежде чем что-либо занести туда. Сделать это Вы можете с помощью следующего фрагмента скрипта:

Function setfocus() { document.first.text1.focus(); }

HTML формы — сложные элементы интерфейса. Они включают в себя разные функциональные элементы: поля ввода и , списки , подсказки и т.д. Весь код формы заключается в элемент .

Большая часть информации веб-форм передаётся с помощью элемента . Для ввода одной строки текста применяется элемент , для нескольких строк - элемент . Элемент создает выпадающий список.

Элемент создаёт надписи к полям формы. Существует два способа группировки надписи и поля. Если поле находится внутри элемента , то атрибут for указывать не нужно.

Last Name Last Name Last Name

Поля формы можно разделять на логические блоки с помощью элемента . Каждому разделу можно присвоить название с помощью элемента .

Контактная информация Имя E-mail
Рис. 1. Группировка полей формы

Чтобы сделать форму более понятной для пользователей, в поля формы добавляют текст, содержащий пример вводимых данных. Такой текст называется подстановочным и создаётся с помощью атрибута placeholder .

Обязательные для заполнения поля также необходимо выделять. До появления HTML5 использовался символ звездочки * , установленный возле названия поля. В новой спецификации появился специальный атрибут required , который позволяет отметить обязательное поле на уровне разметки. Этот атрибут дает указание браузеру (при условии, что тот поддерживает HTML5), указание не отправлять данные после нажатия пользователем кнопки отправить, пока указанные поля не заполнены.

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

Input:focus { background: #eaeaea; }

Ещё один полезный html5-атрибут — атрибут autofocus . Он позволяет автоматически установить фокус на нужном начальном поле для элементов и (только в один элемент каждой формы).

Пример создания формы регистрации

HTML разметка

Регистрация Имя Пол мужской женский E-mail Страна Выберите страну проживания Россия Украина Беларусь Отправить

Примечание
action="form.php" — ссылка на файл обработчика формы. Создайте файл в кодировке UTF-8, закачайте его на сервер и замените action="form.php" на путь к файлу на вашем сервере.


Рис. 2. Внешний вид формы по умолчанию

Как видно из рисунка, каждый элемент формы имеет стили браузера по умолчанию. Очистим стили и оформим элементы формы.

Form-wrap { width: 550px; background: #ffd500; border-radius: 20px; } .form-wrap *{transition: .1s linear} .profile { width: 240px; float: left; text-align: center; padding: 30px; } form { background: white; float: left; width: calc(100% - 240px); padding: 30px; border-radius: 0 20px 20px 0; color: #7b7b7b; } .form-wrap:after, form div:after { content: ""; display: table; clear: both; } form div { margin-bottom: 15px; position: relative; } h1 { font-size: 24px; font-weight: 400; position: relative; margin-top: 50px; } h1:after { content: "\f138"; font-size: 40px; font-family: FontAwesome; position: absolute; top: 50px; left: 50%; transform: translateX(-50%); } /********************** стилизация элементов формы **********************/ label, span { display: block; font-size: 14px; margin-bottom: 8px; } input, input { border-width: 0; outline: none; margin: 0; width: 100%; padding: 10px 15px; background: #e6e6e6; } input:focus, input:focus { box-shadow: inset 0 0 0 2px rgba(0,0,0,.2); } .radio label { position: relative; padding-left: 50px; cursor: pointer; width: 50%; float: left; line-height: 40px; } .radio input { position: absolute; opacity: 0; } .radio-control { position: absolute; top: 0; left: 0; height: 40px; width: 40px; background: #e6e6e6; border-radius: 50%; text-align: center; } .male:before { content: "\f222"; font-family: FontAwesome; font-weight: bold; } .female:before { content: "\f221"; font-family: FontAwesome; font-weight: bold; } .radio label:hover input ~ .radio-control, .radiol input:focus ~ .radio-control { box-shadow: inset 0 0 0 2px rgba(0,0,0,.2); } .radio input:checked ~ .radio-control { color: red; } select { width: 100%; cursor: pointer; padding: 10px 15px; outline: 0; border: 0; background: #e6e6e6; color: #7b7b7b; -webkit-appearance: none; /*убираем галочку в webkit-браузерах*/ -moz-appearance: none; /*убираем галочку в Mozilla Firefox*/ } select::-ms-expand { display: none; /*убираем галочку в IE*/ } .select-arrow { position: absolute; top: 38px; right: 15px; width: 0; height: 0; pointer-events: none; /*активизируем показ списка при нажатии на стрелку*/ border-style: solid; border-width: 8px 5px 0 5px; border-color: #7b7b7b transparent transparent transparent; } button { padding: 10px 0; border-width: 0; display: block; width: 120px; margin: 25px auto 0; background: #60e6c5; color: white; font-size: 14px; outline: none; text-transform: uppercase; } /********************** добавляем форме адаптивность **********************/ @media (max-width: 600px) { .form-wrap {margin: 20px auto; max-width: 550px; width:100%;} .profile, form {float: none; width: 100%;} h1 {margin-top: auto; padding-bottom: 50px;} form {border-radius: 0 0 20px 20px;} }

Файл form.php

Примечание
В переменной $subject укажите текст, который будет отображаться как заголовок письма;
Ваше_имя — здесь вы можете указать имя, которое будет отображаться в поле «от кого письмо» ;
url_вашего_сайта замените на адрес сайта с формой регистрации;
ваш_email замените на ваш адрес электронной почты;
$headers .= "Bcc: ваш_email". "\r\n"; отправляет скрытую копию на ваш адрес электронной почты.

Я нынче ж на ученом кутеже
Твое доверье службой завоюю,
Ты ж мне черкни расписку долговую,
Чтоб мне не сомневаться в платеже.

Мефистофель, в «Фаусте» Гёте

Формы были кратко представлены в предыдущей главе в качестве способа передачи информации, введённой пользователем, через HTTP. Они были разработаны в вебе до появления JavaScript, с тем расчётом, что взаимодействие с сервером происходит при переходе на другую страницу.

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

Поля Веб-форма состоит из любого числа полей ввода, окружённых тегом. HTML предлагает много разных полей, от простых галочек со значениями вкл/выкл до выпадающих списков и полей для ввода текста. В этой книге не будут подробно обсуждаться все виды полей, но мы сделаем небольшой их обзор.

Много типов полей ввода используют тег. Его атрибут type используется для выбора стиля поля. Вот несколько распространённых типов:

text текстовое поле на одну строку
password то же, что текст, но прячет ввод
checkbox переключатель вкл/выкл
radio часть поля с возможностью выбора из нескольких вариантов
file позволяет пользователю выбрать файл на его компьютере

Поля форм не обязательно должны появляться внутри тега. Их можно разместить в любом месте страницы. Информацию из таких полей нельзя передавать на сервер (это возможно только для всей формы целиком), но когда мы делаем поля, которые обрабатывает JavaScript, нам обычно и не нужно передавать информацию из полей через submit.

(text)

(password)

(checkbox)

(radio)

(file)

Интерфейс JavaScript для таких элементов разнится в зависимости от типа. Мы рассмотрим каждый из них чуть позже.

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

один два три

А тег используется для создания поля, которое позволяет пользователю выбрать один из заданных вариантов.
Блины Запеканка Мороженка

Когда значение поля изменяется, запускается событие “change”.

Фокус В отличие от большинства элементов документа HTML, поля форм могут получать фокус ввода клавиатуры. При щелчке или выборе их другим способом они становятся активными, т.е. главными приёмниками клавиатурного ввода.

Если в документе есть текстовое поле, то набираемый текст появится в нём, только если поле имеет фокус ввода. Другие поля по-разному реагируют на клавиатуру. К примеру, пытается перейти на вариант, содержащий текст, который вводит пользователь, а также отвечает на нажатия стрелок, передвигая выбор варианта вверх и вниз.

Управлять фокусом из JavaScript можно методами focus и blur. Первый перемещает фокус на элемент DOM, из которого он вызван, а второй убирает фокус. Значение document.activeElement соответствует текущему элементу, получившему фокус.

document.querySelector("input").focus(); console.log(document.activeElement.tagName); // → INPUT document.querySelector("input").blur(); console.log(document.activeElement.tagName); // → BODY

На некоторых страницах нужно, чтобы пользователь сразу начинал работу с какого-то из полей формы. При помощи JavaScript можно передать этому полю фокус при загрузке документа, но в HTML также есть атрибут autofocus, который приводит к тому же результату, но сообщает браузеру о наших намерениях. В этом случае браузер может отменить это поведение в подходящих случаях, например когда пользователь перевёл фокус куда-то ещё.

Браузеры по традиции позволяют пользователю перемещать фокус клавишей Tab. Мы можем влиять на порядок перемещения через атрибут tabindex. В примере документ будет переносить фокус с текстового поля на кнопку OK, вместо того, чтобы сначала пройти через ссылку help.

(help) OK

По умолчанию, большинство типов элементов HTML не получают фокус. Но добавив tabindex к элементу, вы сделаете возможным получение им фокуса.

Отключённые поля Все поля можно отключить атрибутом disabled, который существует и в виде свойства элемента объекта DOM.

У меня всё хорошо Я в отключке

Отключённые поля не принимают фокус и не изменяются, и в отличие от активных, обычно выглядят серыми и выцветшими.

Когда программа находится в процессе обработки нажатия на кнопку или другой элемент, которое может потребовать общение с сервером и занять длительное время, неплохо отключать элемент до завершения действия. В этом случае, когда пользователь потеряет терпение и нажмёт на элемент ещё раз, действие не будет повторено лишний раз.

Форма в целом Когда поле, содержится в элементе, у его элемента DOM будет свойство form, которое будет ссылаться на форму. Элемент, в свою очередь, имеет свойство elements, содержащее массивоподобную коллекцию полей.

Атрибут name поля задаёт, как будет определено значение этого поля при передаче на сервер. Его также можно использовать как имя свойства при доступе к свойству формы elements, который работает и как объект, похожий на массив (с доступом по номерам), так и map (с доступом по имени).

Имя:
Пароль:
Войти var form = document.querySelector("form"); console.log(form.elements.type); // → password console.log(form.elements.password.type); // → password console.log(form.elements.name.form == form); // → true

Кнопка с атрибутом type равным submit при нажатии отправляет форму. Нажатие клавиши Enter внутри поля формы имеет тот же эффект.

Отправка формы обычно означает, что браузер переходит на страницу, обозначенную в атрибуте формы action, используя либо GET либо POST запрос. Но перед этим запускается свойство “submit”. Его можно обработать в JavaScript, и обработчик может предотвратить поведение по умолчанию, вызвав на объекте event preventDefault.

Значение: Сохранить var form = document.querySelector("form"); form.addEventListener("submit", function(event) { console.log("Saving value", form.elements.value.value); event.preventDefault(); });

Перехват событий “submit” полезен в нескольких случаях. Мы можем написать код, проверяющий допустимость введённых значений и сразу же показать ошибку вместо передачи данных формы. Или мы можем отключить отправку формы по умолчанию и дать программе возможность самой обработать ввод, например используя XMLHttpRequest для отправки данных на сервер без перезагрузки страницы.

Текстовые поля Поля с тегами и типами text и password, а также теги, имеют общий интерфейс. У их элементов DOM есть свойство value, в котором содержится их текущее содержимое в виде строки текста. Присваивание этому свойству значения меняет содержимое поля.

Свойства текстовых полей selectionStart и selectionEnd содержат данные о положении курсора и выделения текста. Когда ничего не выделено, их значение одинаковое, и равно положению курсора. Например, 0 обозначает начало текста, 10 обозначает, что курсор находится на 10-м символе. Когда выделена часть поля, свойства имеют разные значения, а именно начало и конец выделенного текста. В эти поля также можно записывать значение.

К примеру, представьте, что вы пишете статью про Khasekhemwy, но затрудняетесь писать его имя правильно. Следующий код назначает тегу обработчик событий, который при нажатии F2 вставляет строку “ Khasekhemwy”.

var textarea = document.querySelector("textarea"); textarea.addEventListener("keydown", function(event) { // The key code for F2 happens to be 113 if (event.keyCode == 113) { replaceSelection(textarea, "Khasekhemwy"); event.preventDefault(); } }); function replaceSelection(field, word) { var from = field.selectionStart, to = field.selectionEnd; field.value = field.value.slice(0, from) + word + field.value.slice(to); // Put the cursor after the word field.selectionStart = field.selectionEnd = from + word.length; };

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

Событие “change” для текстового поля не срабатывает каждый раз при вводе одного символа. Оно срабатывает после потери полем фокуса, когда его значение было изменено. Чтобы мгновенно реагировать на изменение текстового поля нужно зарегистрировать событие “input”, которое срабатывает каждый раз при вводе символа, удалении текста или других манипуляциях с содержимым поля.

В следующем примере мы видим текстовое поле и счётчик, показывающий текущую длину введённого текста.

length: 0 var text = document.querySelector("input"); var output = document.querySelector("#length"); text.addEventListener("input", function() { output.textContent = text.value.length; });

Галочки и радиокнопки Поле галочки – простой бинарный переключатель. Его значение можно извлечь или поменять через свойство checked, содержащее булевскую величину.

Сделать страницу фиолетовой var checkbox = document.querySelector("#purple"); checkbox.addEventListener("change", function() { document.body.style.background = checkbox.checked ? "mediumpurple" : ""; });

Тег используется для связи куска текста с полем ввода. Атрибут for должен совпадать с id поля. Щелчок по метке label включает поле ввода, оно получает фокус и меняет значение – если это галочка или радиокнопка.

Радиокнопка схожа с галочкой, но она связана с другими радиокнопками с тем же именем, так что только одна из них может быть выбрана.

Цвет: Фиолетовый Зелёныйы Голубой var buttons = document.getElementsByName("color"); function setColor(event) { document.body.style.background = event.target.value; } for (var i = 0; i < buttons.length; i++) buttons[i].addEventListener("change", setColor);

Метод document.getElementsByName выдаёт все элементы с заданным атрибутом name. Пример перебирает их (посредством обычного цикла for, а не forEach, потому что возвращаемая коллекция – не настоящий массив) и регистрирует обработчик событий для каждого элемента. Помните, что у объектов событий есть свойство target, относящееся к элементу, который запустил событие. Это полезно для создания обработчиков событий – наш обработчик может быть вызван разными элементами, и у него должен быть способ получить доступ к текущему элементу, который его вызвал.

Поля select Поля select похожи на радиокнопки – они также позволяют выбрать из нескольких вариантов. Но если радиокнопки позволяют нам контролировать раскладку вариантов, то вид поля определяет браузер.

У полей select есть вариант, больше похожий на список галочек, чем на радиокнопки. При наличии атрибута multiple тег позволит выбирать любое количество вариантов, а не один.

Блины Запеканка Мороженка

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

Атрибут size тега используется для задания количества вариантов, которые видны одновременно – так вы можете влиять на внешний вид выпадушки. К примеру, назначив size 3, вы увидите три строки одновременно, безотносительно того, присутствует ли опция multiple.

У каждого тега есть значение. Его можно определить атрибутом value, но если он не задан, то значение тега определяет текст, находящийся внутри тега.. . Свойство value элемента отражает текущий выбранный вариант. Для поля с возможностью выбора нескольких вариантов это свойство не особо нужно, т.к. в нём будет содержаться только один из нескольких выбранных вариантов.

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

Следующий пример извлекает выбранные значения из поля select и использует их для создания двоичного числа из битов. Нажмите Ctrl (или Command на Маке), чтобы выбрать несколько значений сразу.

0001 0010 0100 1000 = 0 var select = document.querySelector("select"); var output = document.querySelector("#output"); select.addEventListener("change", function() { var number = 0; for (var i = 0; i < select.options.length; i++) { var option = select.options[i]; if (option.selected) number += Number(option.value); } output.textContent = number; });

Файловое поле Файловое поле изначально было предназначено для закачивания файлов с компьютера через форму. В современных браузерах они также позволяют читать файлы из JavaScript. Поле работает как охранник для файлов. Скрипт не может просто взять и открыть файл с компьютера пользователя, но если тот выбрал файл в этом поле, браузер разрешает скрипту начать чтение файла.

Файловое поле обычно выглядит как кнопка с надписью вроде «Выберите файл», с информацией про выбранный файл рядом с ней.

var input = document.querySelector("input"); input.addEventListener("change", function() { if (input.files.length > 0) { var file = input.files; console.log("You chose", file.name); if (file.type) console.log("It has type", file.type); } });

Свойство files элемента – массивоподобный объект (не настоящий массив), содержащий список выбранных файлов. Изначально он пуст. У элемента нет простого свойства file, потому что пользователь может выбрать несколько файлов за раз при включённом атрибуте multiple.

У объектов в свойстве files есть свойства имя (имя файла), размер (размер файла в байтах), и тип (тип файла в смысле media type - text/plain или image/jpeg).

Чего у него нет, так это свойства, содержащего содержимое файла. Чтобы получить содержимое, приходиться постараться. Так как чтение файла с диска занимает длительное время, интерфейс должен быть асинхронным, чтобы документ не замирал. Конструктор FileReader можно представлять себе, как конструктор XMLHttpRequest, только для файлов.

var input = document.querySelector("input"); input.addEventListener("change", function() { Array.prototype.forEach.call(input.files, function(file) { var reader = new FileReader(); reader.addEventListener("load", function() { console.log("File", file.name, "starts with", reader.result.slice(0, 20)); }); reader.readAsText(file); }); });

Чтение файла происходит при помощи создания объекта FileReader, регистрации события “load” для него, и вызова его метода readAsText с передачей тому файла. По окончанию загрузки в свойстве result сохраняется содержимое файла.

Пример использует Array.prototype.forEach для прохода по массиву, так как в обычном цикле было бы неудобно получать нужные объекты file и reader от обработчика событий. Переменные были бы общими для всех итераций цикла.

У FileReaders также есть событие “error”, когда чтение файла не получается. Объект error будет сохранён в свойстве error. Если вы не хотите забивать голову ещё одной неудобной асинхронной схемой, вы можете обернуть её в обещание (см. главу 17):

Function readFile(file) { return new Promise(function(succeed, fail) { var reader = new FileReader(); reader.addEventListener("load", function() { succeed(reader.result); }); reader.addEventListener("error", function() { fail(reader.error); }); reader.readAsText(file); }); }

Хранение данных на стороне клиента Простые HTML-странички с добавкой JavaScript могут выступать отличной основой для мини-приложений – небольших вспомогательных программ, автоматизирующих ежедневные дела. Присоединив к полям формы обработчики событий вы можете делать всё – от конвертации фаренгейтов в цельсии до генерации паролей из основного пароля и имени веб-сайта.

Когда такому приложению нужно сохранять информацию между сессиями, переменные JavaScript использовать не получится – их значения выбрасываются каждый раз при закрытии страницы. Можно было бы настроить сервер, подсоединить его к интернету и тогда приложение хранило бы ваши данные там. Это мы разберём в главе 20. Но это добавляет вам работы и сложности. Иногда достаточно хранить данные в своём браузере. Но как?

Можно хранить строковые данные так, что они переживут перезагрузку страниц - для этого надо положить их в объект localStorage. Он разрешает хранить строковые данные под именами (которые тоже являются строками), как в этом примере:

LocalStorage.setItem("username", "marijn"); console.log(localStorage.getItem("username")); // → marijn localStorage.removeItem("username");

Переменная в localStorage хранится, пока её не перезапишут, удаляется при помощи removeItem или очисткой локального хранилища пользователем.

У сайтов с разных доменов – разные отделения в этом хранилище. То есть, данные, сохранённые с вебсайта в localStorage, могут быть прочтены или перезаписаны только скриптами с этого же сайта.

Также браузеры ограничивают объём хранимых данных, обычно в несколько мегабайт. Это ограничение, вкупе с тем фактом, что забивание жёстких дисков у людей не приносит прибыли, предотвращает отъедание места на диске.

Следующий код реализует простую программу для ведения заметок. Она хранит заметки в виде объекта, ассоциируя заголовки с содержимым. Он кодируется в JSON и хранится в localStorage. Пользователь может выбрать записку через поле и поменять её текст в. Добавляется запись по нажатию на кнопку.

Заметки: новая
var list = document.querySelector("#list"); function addToList(name) { var option = document.createElement("option"); option.textContent = name; list.appendChild(option); } // Берём список из локального хранилища var notes = JSON.parse(localStorage.getItem("notes")) || {"что купить": ""}; for (var name in notes) if (notes.hasOwnProperty(name)) addToList(name); function saveToStorage() { localStorage.setItem("notes", JSON.stringify(notes)); } var current = document.querySelector("#currentnote"); current.value = notes; list.addEventListener("change", function() { current.value = notes; }); current.addEventListener("change", function() { notes = current.value; saveToStorage(); }); function addNote() { var name = prompt("Имя записи", ""); if (!name) return; if (!notes.hasOwnProperty(name)) { notes = ""; addToList(name); saveToStorage(); } list.value = name; current.value = notes; }

Скрипт инициализирует переменную notes значением из localStorage, а если его там нет – простым объектом с одной записью «что купить». Попытка прочесть отсутствующее поле из localStorage вернёт null. Передав null в JSON.parse, мы получим null обратно. Поэтому для значения по умолчанию можно использовать оператор || .

Когда данные в note меняются (добавляется новая запись или меняется текущая), для обновления хранимого поля вызывается функция saveToStorage. Если б мы рассчитывали, что у нас будут храниться тысячи записей, это было бы слишком накладно, и нам пришлось бы придумать более сложную процедуру для хранения – например, своё поле для каждой записи.

Когда пользователь добавляет запись, код должен обновить текстовое поле, хотя у поля и есть обработчик “change”. Это нужно потому, что событие “change” происходит, только когда пользователь меняет значение поля, а не когда это делает скрипт.

Есть ещё один похожий на localStorage объект под названием sessionStorage. Разница между ними в том, что содержимое sessionStorage забывается по окончанию сессии, что для большинства браузеров означает момент закрытия.

Итог HTML предоставляет множество различных типов полей формы – текстовые, галочки, множественного выбора, выбора файла.

Из JavaScript можно получать значение и манипулировать этими полями. По изменению они запускают событие “change”, по вводу с клавиатуры – “input”, и ещё много разных клавиатурных событий. Они помогают нам отловить момент, когда пользователь взаимодействует с полем ввода. Свойства вроде value (для текстовых полей и select) или checked (для галочек и радиокнопок) используются для чтения и записи содержимого полей.

При передаче формы происходит событие “submit”. Обработчик JavaScript затем может вызвать preventDefault этого события, чтобы остановить передачу данных. Элементы формы не обязаны быть заключены в теги.

Когда пользователь выбрал файл с жёсткого диска через поле выбора файла, интерфейс FileReader позволит нам добраться до содержимого файла из программы JavaScript.

Объекты localStorage и sessionStorage можно использовать для хранения информации таким способом, который переживёт перезагрузку страницы. Первый сохраняет данные навсегда (ну или пока пользователь специально не сотрёт их), а второй – до закрытия браузера.

УпражненияВерстак JavaScript Сделайте интерфейс, позволяющий писать и исполнять кусочки кода JavaScript.

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

return "hi"; Поехали // Ваш код.

Автодополнение Дополните текстовое поле так, что при вводе текста под ним появлялся бы список вариантов. У вас есть массив возможных вариантов, и показывать нужно те из них, которые начинаются с вводимого текста. Когда пользователь щёлкает по предложенному варианту, он меняет содержимое поля на него.

// Строит массив из имён глобальных перменных, // типа "alert", "document", и "scrollTo" var terms = ; for (var name in window) terms.push(name); // Ваш код.

Игра «Жизнь» Конвея Это простая симуляция жизни на прямоугольной решётке, каждый элемент которой живой или нет. Каждое поколение (шаг игры) применяются следующие правила:

Каждая живая клетка, количество соседей которой меньше двух или больше трёх, погибает
- каждая живая клетка, у которой от двух до трёх соседей, живёт до следующего хода
- каждая мёртвая клетка, у которой есть ровно три соседа, оживает

Соседи клетки – это все соседние с ней клетки по горизонтали, вертикали и диагонали, всего 8 штук.

Обратите внимание, что правила применяются ко всей решётке одновременно, а не к каждой из клеток по очереди. То есть, подсчёт количества соседей происходит в один момент перед следующим шагом, и изменения, происходящие на соседних клетках, не влияют на новое состояние клетки.

Реализуйте игру, используя любые подходящие структуры. Используйте Math.random для создания случайных начальных популяций. Выводите поле как решётку из галочек с кнопкой «перейти на следующий шаг». Когда пользователь включает или выключает галочки, эти изменения нужно учитывать при подсчёте следующего поколения.

Следующее поколение // Ваш код.

Похожие статьи