Учимся делать веб-сайты с нуля до трудоустройства. Разбираемся, как делать дизайн и верстку. Сегодня познакомимся с Javascript. С его помощью сделаем, чтобы при клике на кнопку открывалось модальное окно и сделаем проверку корректности заполнения контактной формы.
Для тех, кто хочет индивидуальное обучение с преподавателем и трудоустройство: пишите нам в телеграм:
Что было на прошлом занятии?
Мы научились делать модальное диалоговое окно с помощью html и css.
Вот ссылка на архив с результатами прошлого урока:
https://github.com/madmaker/srmt22-lsn12/archive/refs/tags/v1.zip
Скачайте себе этот архив, распакуйте и откройте в vsCode. На его основе мы будем делать этот урок.
Что будет на этом уроке?
На этом уроке мы научимся:
- Работать с Javascript
- Реагировать на нажатие кнопки
- Управлять отображением элементов на странице с помощью Javascript
- Проверять корректность заполнения полей ввода в контактной форме с помощью Javascript
- Научимся отлаживать JS код в консоли браузера.
Если в процессе изучения что-то не понятно - не стесняйтесь спрашивать нас и других учеников в нашей открытой группе в телеграм:
Для тех, кто только к нам присоединился, ссылка на все уроки:
Ссылка на самый первый урок:
Изучаем Javascript
Что ж, мы разобрались с html и css. На самом деле это не языки программирования. HTML - язык разметки. CSS - описание стиля. Но без них никуда - страницы и их элементы описываются в html и css.
А Javascript уже очень даже серьезный язык программирования. На нем одном можно писать и сайты, и серверы, и десктопные и мобильные приложения. Мы в нашем обучении сейчас будем использовать для программирования frontend части приложения (та, которая в браузере), а для бэкенда будем использовать PHP.
У нас курс практический. Поэтому мы погружаемся в теорию в процессе практики.
У нас сейчас задача: при клике на кнопку "Вступить в клуб бесплатно" открывать модальное окно.
Эксперименты с Javascript в консоли браузера
Откройте консоль браузера и переключитесь во вкладку "Консоль"
Если вкладок не видно - сделайте правую панель пошире.
Как открывать панель инструментов разработчика мы рассматривали в Уроке 9 в разделе "Консоль браузера".
Если вам нужно будет посмотреть html-код страницы и поработать со стилями, переключитесь назад во вкладку "Элементы".
Итак, вкладка "Консоль".
В ней можно писать код Javascript и после нажатия Enter он выполнится.
JS Hello World
В консоли пишем alert("Hello world") и жмем Enter
Отобразится Alert с заданным нами текстом.
console.log()
Попробуйте написать console.log("hello world")
Вы увидите, как в консоли появится текст "Hello world"
console.log - очень удобный инструмент для отладки скриптов JS. Если нужно что-то проверить - можно воспользоваться этим инструментом. Текст будет отображаться только в консоли браузера. Обычный рядовой пользователь его не увидит и ему это никак не помешает работе с сайтом.
DOM
Как нам говорит Википедия:
DOM (от англ. Document Object Model — «объектная модель документа») — это независящий от платформы и языка программный интерфейс, позволяющий программам и скриптам получить доступ к содержимому HTML-, XHTML- и XML-документов, а также изменять содержимое, структуру и оформление таких документов.
На пальцах - это наш html-код страницы, которым мы можем манипулировать с помощью Javascript.
https://github.com/madmaker/srmt22-lsn12/archive/refs/tags/v1.zip
Скачайте по ссылке выше код с результатами прошлого занятия, распакуйте и откройте папку проекта в любой IDE: vscode или phpstorm.
Файл index.html откройте в браузере.
У нас в index.html есть контейнер модального окна <div class="modal">. Давайте ему назначим ID, например "modal-join-us".
Код меняем так:
<div class="modal" id="modal-join-us">
Доступ к DOM через Javascript
В Javascript мы можем манипулировать любыми элементами на странице. Главное правильно к ним обратиться.
Самый простой способ - это по ID. Мы нашему диалоговому окну задали ID только что. Поэтому можем легко к нему обратиться в JS. Делается это так:
document.getElementById("modal-join-us")
Попробуйте выполнить этот код в консоли браузера.
Консоль вернет ссылку на объект на странице.
Управление стилем элемента через Javascript
Давайте еще раз: document - это наш документ - наша страница
getElementById() - это метод объекта document - он возвращает объект DOM.
У объекта DOM есть свойство "style" - это стиль. Можно задавать css стиль таким образом.
Есть объект className - считывать имя класса объекта.
Попробуйте выполнить код в консоли:
document.getElementById("modal-join-us").className
Консоль вернет 'modal' - имя класса выбранного объекта.
Давайте сделаем display:none для нашего модального окна через Javascript.
Выполните этот код в консоли:
document.getElementById("modal-join-us").style.display = "none"
Диалог пропадет.
Давайте теперь отобразим его (вернем значение display, как было):
document.getElementById("modal-join-us").style.display = "grid"
Выбираем объект DOM с помощью document.querySelector()
Мы разобрались с тем, как обращаться к объектам DOM по ID с помощью getElementByID.
Есть еще один удобный способ: document.querySelector().
Обращаемся к modal-join-us по ID по принципу CSS - через решетку.
document.querySelector("#modal-join-us")
Сработает точно также - в консоль вернет объект этого элемента.
И по аналогии с CSS мы можем "добраться" до контейнера кнопки-крестика в этом диалоге:
document.querySelector("#modal-join-us .close-cross-btn")
Попробуйте выполнить в консоли.
Закрываем модальное окно при клике на крестик с помощью JS
Собственно, как с помощью JS найти кнопку-крестик, мы разобрались. Теперь нам нужно перехватить событие клика на эту кнопку.
Сначала разберем простой пример, а потом поговорим о функциях в программировании.
document.querySelector("#modal-join-us .close-cross-btn").addEventListener("click",()=>{alert("кнопка нажата")})
Выполните этот код в консоли браузера, а потом нажмите на крестик закрытия диалога.
Давайте теперь разберемся, как мы этого добились.
document.querySelector("#modal-join-us .close-cross-btn") Так мы обратились к объекту контейнера кнопки с крестиком.
addEventListener()
Так мы повесили на объект наблюдение за событиями
click
В addEventListener() первым аргументом указали событие click. Вторым аргументом указали код, который выполнится при происхождении этого события. А в коде мы указали функцию, которая вызовет alert() на экран.
Функции в Javascript
Функции - это один из основных инструментов в языке программирования. Смысл функции в том, что мы в ней описываем сценарий, который будет выполнятся, когда вызовут эту функцию.
Давайте разберемся на практике
function test () {
console.log('test1');
console.log('test2');
console.log('test3');
document.querySelector("#modal-join-us").style.display="none";
alert("alert");
}
function test - это объявление функции. Начинается с ключевого слова function.
В фигурных скобках ее определение.
В круглых скобках функции передаются аргументы (чуть позже о них). Аргументов может и не быть (пустые круглые скобки).
В фигурных скобках - тело функции. Ее определение.
Вызов функции производится таким образом:
test()
То есть пишем имя функции и круглые скобки за ним.
Давайте выполним следующий код в консоли барузера:
function test () {
console.log('test1');
console.log('test2');
console.log('test3');
document.querySelector("#modal-join-us").style.display="none"; }
Результатом выполнения этого кода визуально не будет ничего. Пока мы функцию не вызовем, ничего не произойдет.
А теперь попробуйте вызвать эту функцию в консоли браузера:
test()
Функция в консоль выведет 3 строки текста и спрячет диалоговое окно.
Аргументы функции
Давайте улучшим нашу функцию. Добавим ей аргумент displayValue.
function test (displayValue) {
document.querySelector("#modal-join-us").style.display=displayValue;
}
Выполните этот код в консоли браузера.
Теперь выполните этот код:
test("none");
А потом этот:
test("grid")
Наш диалог будет скрываться и отображаться при вызове функции с разными аргументами.
Как это работает?
В определении функции мы указали один принимаемый функцией аргумент: displayValue.
В теле функции мы этот аргумент используем, как переменную вместо "grid" или "none", когда задаем значение display. То есть вместо простого текста в display мы используем переменную displayValue, которая передается аргументом в функцию.
Когда мы вызываем функцию, мы передаем значение аргумента в круглых скобках. Функция этот аргумент использует как переменную и подставляет ее значение при назначении стиля display.
Ветвление If else в Javascript
Еще одна из основ программирования: ветвление.
Давайте разберем на примере нашей функции, которая отображает и прячет диалоговое окно.
function test (show) {
if(show==1) {
displayValue='grid';
}
else {
displayValue="none";
}
document.querySelector("#modal-join-us").style.display=displayValue;
}
Давайте в консоли браузера выполним код с определением этой функции.
А теперь попробуем вызвать эту функцию по-новому:
test(1)
Диалог будет отображен
test(0)
Диалог будет скрыт.
Как это работает?
if(условие) {
код, который должен выполняться, если выражение в условии верно (true)
}
else {
код, который должен выполняться, если выражение в условии не верно (false)
}
То есть мы в круглых скобках после if() задаем выражение, которое проверяется. Если оно соответствует действительности, то код в фигурных скобках выполняется.
Если выражение в if не соответствует действительности, то выполняется код в ветке else {}
Операторы сравнения, true, false, отрицание "!"
Всем знакомы операторы сравнения из математики: > и <.
if(1>0) - правда - вернет true и код в ветке if() выполнится.
if(5<3) - ложь - вернет false и код в ветке if() не выполнится, а выполнится ветка else {}.
Как сравнить на соответствие? То есть как проверить, что 5=5?
Для этого есть оператор сравнения ==.
if(1==0) вернет false
if(5==5) вернет true.
Чтобы проверить на "одно равно другому" используем ==.
Чтобы проверить на "одно НЕ равно другом" используем !=.
Восклицательный знак отрицает значение, которое идет за ним.
То есть true равно true. И при этом true равно !false. Можно читать восклицательный знак, как НЕ - отрицание.
Итого:
if(1>3) - false
if(1<3) - true
if(1==3) - false
if(1!=3) - true.
Еще раз разберем код нашей функции:
function test (show) {
Объявляем функцию с одним аргументом show
if(show==1) {
Если значение show равно 1, то код в этой ветке выполнится
displayValue='grid';
В этой ветке в переменную displayValue мы записываем значение grid
}
else {
Если show не равно 1, то выполнится код в ветке else
displayValue="none";
В этой ветке в переменную displayValue мы записываем значение none
}
document.querySelector("#modal-join-us").style.display=displayValue;
Задаем значение display в стиле диалогового окна
}
True=1, false=0
Еще один момент в программировании: В языках программирования true - тоже самое, что 1, а false - тоже самое, что 0.
Поэтому наше выражение if(show==1) избыточно. Мы можем просто оставить if(show).
Если show будет равно 1, то фактически для JS выражение if(show) будет значить if(true), а если show будет не равно 1, то if(show) для языка программирования будет тоже самое, что if(false).
if, if else, else
Еще одна возможность ветвления, которую стоит осветить:
Может быть несколько веток, а не только if и else.
Например, может быть так:
if(show) {
//Выполнится, если show == 1
}
else if(show==3) {
//Выполнится, если show == 3
}
else if (show==4) {
//Выполнится, если show==4
}
else {
//Выполнится во всех остальных случаях
}
Наравне с этим может быть всего одна ветка:
if(show==5) {
//Выполнится, если show==5
}
//Все. Если show не равно 5, то больше никаких веток - сценарий просто будет дальше выполняться. Без else. То есть то, что написано в фигурных скобках либо выполнится, либо просто будет пропущено и программа продолжит дальше
Сокращенное написание if-else
Мы можем писать так:
if(условие) {
1 код для выполнения
}
else {
2 код для выполнения
}
Либо так:
условие?1 код для выполнения:2 код для выполнения
Это очень удобно, если нужно if-else использовать где-то на месте.
Например, мы можем вот этот код упростить:
function test (show) {
if(show) {
displayValue='grid';
}
else {
displayValue="none";
}
document.querySelector("#modal-join-us").style.display=displayValue;
}
Причем упростить до безобразия :)
function test (show) {
document.querySelector("#modal-join-us").style.display=show?"grid":"none";
}
То есть мы прям на месте в зависимости от значения show определяем: если show==1, то используем "grid", иначе используем "none".
Строки всегда в скобках
Важный момент. Текст, строки всегда оборачиваются в скобки: двойные или одинарные.
То есть "grid" - строка, а grid без скобок - это ошибка.
displayValue без скобок - это переменная, которую мы выше задавали. А "displayValue" в скобках - это строка, просто обычный текст.
Резюмируем:
Строки в скобках - "строка"
За именем функции следуют круглые скобки - test()
Переменные без скобок - displayValue
Скрываем диалог при клике на кнопку-крестик
Возвращаемся к нашему диалогу.
Мы выработали отличную функцию, которая, при ее вызове, в зависимости от значения аргумента, переданного в нее, либо спрячет, либо отобразит диалог.
function test (show) {
document.querySelector("#modal-join-us").style.display=show?"grid":"none";
}
Мы разобрались, как "повесить" выполнение этой функции при клике на кнопку-крестик.
document.querySelector("#modal-join-us .close-cross-btn").addEventListener("click",function() { test(1) })
Еще раз про addEventListener().
Он принимает два аргумента:
- Событие, которое наблюдается - в нашем случае click
- Код, которые должен выполняться. Он оборачивается в функцию.
Стрелочные функции JS
Обычным способом синтаксис создания функции выглядит так:
function test (arg1, arg2) {
тело функции
}
Есть упрощенный синтаксис.
test = (arg1,arg2)=>{тело функции}
Если аргумент всего один, то можно круглые скобки опустить
test = arg1 => {тело функции}
Если аргументов нет, то круглые скобки должны быть написаны пустыми
test = () => {тело функции}
Если в теле функции всего одна строка или команда, например alert("Hello world"), то фигурные скобки можно опустить
test = () => alert("Hello world")
Это я все к тому, что можно упростить вот этот код:
document.querySelector("#modal-join-us .close-cross-btn").addEventListener("click",function() { test(1) })
Со стрелочной функцией будет так:
document.querySelector("#modal-join-us .close-cross-btn").addEventListener("click", ()=>test(1) )
Сохраняем код в .js файл
Все, с браузером мы наэкспериментирвоались. Давайте сохранять результаты в файл и использовать их на странице.
Создаем папку js в корне проекта и в ней файл modals.js
В modal.js добавим такой код:
function showModal (show) {
document.getElementByid("modal-join-us").style.display=show?"grid":"none";
}
document.querySelector("#modal-join-us .close-cross-btn").addEventListener("click",()=>showModal(0))
Обратите внимание, что я переименовал функцию в showModal().
Еще обратите внимание на то, как принято называть функции в JS: с маленькой буквы и каждое новое слово слитно с большой буквы.
Этот стиль называется CamelCase.
В index.html нужно подключить наш файд modal.js.
В самый конец кода перед закрывающим тегом </body> добавляем следующий код:
<script type="text/javascript" src="js/modals.js" async></script>
В целом все понятно кроме async.
async говорит браузеру загружать этот файл асинхронно с загрузкой страницы. Если грузить синхронно, то страница не считается загруженной на 100% пока не загрузятся все скрипты, стили и прочие файлы. А если сказать браузеру грузить скрипт асинхронно, то браузер будет считать, что страница загрузилась даже если скрипт еще загружается.
Открываем диалог при клике на кнопку
Действовать будем по уже знакомой по этому уроку методике:
- Кнопке "Вступить в клуб" добавим id.
- Добавим Event Listener на событие click и вызовем нашу функцию, но со значение аргумента show равным 1
Теперь при клике на крестик в диалоге он закрывается. А при клике на кнопку "Вступить в клуб" диалог открывается.
Закрываем диалог при клике на фон диалога
Тут все несколько хитрей.
В случае с кнопкой-крестиком все понятно: на нее кликнули, событие перехватили и выполнили код по этому событию.
В случае с подложкой диалога так просто не выйдет. Подложка перекрывает все окно и находится под самим диалогом. И даже если кликнуть на диалог, клик на подложку тоже сработает, потому что она под диалогом тоже есть.
В этом случае нужно сделать проверку события и проверить на какой конкретно объект произошел непосредственный клик.
document.getElementById("modal-join-us").addEventListener("click",(e) => e.target==document.getElementById("modal-join-us")?showModal(0):{})
Разберем этот код по частям.
document.getElementById - мы знаем id элемента и лучше обращаться к нему по getElementById вместо document.querySelector, так как второй в два раза медленней работает (с другой стороны, разница настолько мизерна: 15 миллионов операций getElementById против 7 миллионов у querySelector, но все же).
В addEventListener вторым аргументом мы передаем стрелочную функцию. разложим ее в обычном синтаксисе без сокращенных вариантов здесь:
function (e) {
if(e.target == document.getElementById("modal-join-us")) {
showModal(0)
}
}
В функцию мы передаем аргумент e - это произошедшее событие.
У события есть свойство target. Мы к свойствам обращаемся через точку, поэтому e.target.
В target хранится объект, по которому был непосредственный клик.
Мы сравниваем этот объект с нашим объектом modal-join-us, который получаем через document.getElementById("modal-join-us").
Если это один и тот же объект, то оператор сравнения == вернет true и код в теле функции отработает - будет выполнено скрытие диалога.
Резюмирую: все почти точно также, как с кликом на кнопку-крестик, но пришлось сделать дополнительную проверку, чтобы убедиться, что клик был произведен именно на подложку, а не на какой-то элемент над ней.
Добавляем код в modal.js
Проверяем в браузере.
Скрываем диалог в исходном состоянии
Когда у нас открывается страница, сейчас диалог отображается поверх всего сайта. А нам нужно, чтобы он был скрыт изначально.
Собственно, тут все просто: заменим у диалога display:grid на display:none;
Добавляем проверку заполнения поля номера телефона
У нас есть код поля с номером телефона:
<input type="tel" name="phone" placeholder="+79991112233">
Давайте обозначим это поле, как обязательное к заполнению - просто добавим атрибут required
И добавим проверку значения этого поля - добавим атрибут pattern со следующим значением:
pattern="\+[0-9]{9,13}"
Значение в паттерне - это регулярное выражение. Простыми словами это шаблон, которому должно соответствовать значение поля. Если не соответствует - форма не будет отправлена и вылезет ошибка. Если будет соответствовать - форма отправится.
Про регулярные выражения мы будем позже еще не раз разговаривать, но сейчас я вклатце расшифрую эту запись.
+ - первый символ номера телефона в федеральном формате.
Перед плюсом стоит обратный слэш (\ - он же бэкслэш). Дело в том, что плюс в регулярных выражениях - это спецсимвол, а не просто текстовый символ. Чтобы объяснить браузеру, что мы хотим самый обычный плюс, а не спецсимвол, мы применяем экранирование с помощью бэкслэша. То есть если поставить бэкслэш перед спецсимволом, то он будет восприниматься как обычный текст.
[0-9] - в квадратных скобках у нас группа возможных значений. Цифры можно не через запятую записывать, а указать диапазон от и до, то есть от 0 до 9.
{9,13} - в фигурных скобках мы задаем требуемое количество того, что было слева от фигурных скобок, то есть цифр от 0 до 9. Первое число в фигурных скобках - это минимум, второе - это максимум. То есть мы требуем от 9 до 13 цифр от 0 до 9.
Итого, регулярное выражение работать будет так:
Значение должно начинаться с плюса, дальше должно быть от 9 до 13 цифр от 0 до 9.
В федеральных номерах в России 11 цифр, но давайте не будем забывать о номерах других стран: у них может быть другое количество. Поэтому расширим несколько диапазон .
Итого новый код такой:
В целом все - при корректном заполнении поля наша форма отправится на сервер. На этом этапе мы и остановимся на этом уроке с отправкой формы. Процесс отправки на сервер и дальнейшее поведение диалога и формы мы будем рассматривать на этапе обработки на сервере.
Для тех, кому интересно сравнить результаты выполнения с моим кодом, ссылка на арихв ниже:
https://github.com/madmaker/srmt22-lsn13/archive/refs/tags/v1.zip
Резюме урока
Поздравляю, мы познакомились с Javascript. Вы поработали с DOM, с функциями, с ветвлением, с событиями, со стрелочными функциями.
Практики пока мало. Все у нас пройдено в режиме знакомства скорее пока, но, немного подтянув навыки и потренировавшись, с этим набором знаний можно пробовать устраиваться Junior Frontend разработчиком.
С чем вы уже знакомы?
- HTML
- CSS
- SASS
- Javascript
- Docker
- Linux-серверы
- Верстка
- Дизайн сайтов
Что делать дальше и как нам помочь?
1. Поставить лайк
2. Написать в комментарии, за сколько времени удалось сделать урок, с чем возникли сложности, что бы хотелось разобрать более детально
3. Подписаться на этот канал
4. Добавиться к нам в группу в наш открытый клуб веб-разработки в телеграм: https://t.me/srmt22_webclub
5. Сделать репост этого урока себе в соцсети.
Что будет на следующем занятии?
Начнем изучать Docker, NginX, PHP. Погрузимся в дебри бэкэнд-разработки.
Трудоустройство
Те, кто хочет индивидуальное обучение с преподавателем и быстрое гарантированное трудоустройство, пишите нам в телеграм: