От автора: в этой статье мы создадим веб-приложение — конвертер цветов RGB и шестнадцатеричного кода.
Вы можете найти демо здесь, а исходный код здесь.
Структура проекта довольно проста.
index.html: содержит структуру приложения.
style.css: стили страницы.
app.js: содержит весь код, необходимый для запуска проекта.
Вот список вещей, которые я хотел, чтобы выполняло это приложение:
Всякий раз, когда что-то набирается в текстовом поле для шестнадцатеричного числа, приложение должно проверять, является ли цвет действительным. Если это так, преобразует его в RGB, устанавливает в качестве фона, а затем помещает значение RGB в текстовое поле RGB и наоборот.
Если в текстовое поле введен короткий шестнадцатеричный код цвета, расширяет его, когда с текстового поля снимается фокус (пользователь кликает за пределами текстовой области).
Автоматически добавляет символ к шестнадцатеричному вводу «#».
Давай начнем!
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Hex to RGB Converter</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="head"> HEX <--> RGB </div> <div id="content"> <input type="text" id="hex" placeholder="hex"> <img id="hexError" class="hidden" src="data:image/svg+xml;utf8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIj48cGF0aCBkPSJNNTY5LjUxNyA0NDAuMDEzQzU4Ny45NzUgNDcyLjAwNyA1NjQuODA2IDUxMiA1MjcuOTQgNTEySDQ4LjA1NGMtMzYuOTM3IDAtNTkuOTk5LTQwLjA1NS00MS41NzctNzEuOTg3TDI0Ni40MjMgMjMuOTg1YzE4LjQ2Ny0zMi4wMDkgNjQuNzItMzEuOTUxIDgzLjE1NCAwbDIzOS45NCA0MTYuMDI4ek0yODggMzU0Yy0yNS40MDUgMC00NiAyMC41OTUtNDYgNDZzMjAuNTk1IDQ2IDQ2IDQ2IDQ2LTIwLjU5NSA0Ni00Ni0yMC41OTUtNDYtNDYtNDZ6bS00My42NzMtMTY1LjM0Nmw3LjQxOCAxMzZjLjM0NyA2LjM2NCA1LjYwOSAxMS4zNDYgMTEuOTgyIDExLjM0Nmg0OC41NDZjNi4zNzMgMCAxMS42MzUtNC45ODIgMTEuOTgyLTExLjM0Nmw3LjQxOC0xMzZjLjM3NS02Ljg3NC01LjA5OC0xMi42NTQtMTEuOTgyLTEyLjY1NGgtNjMuMzgzYy02Ljg4NCAwLTEyLjM1NiA1Ljc4LTExLjk4MSAxMi42NTR6Ii8+PC9zdmc+" /> </br> <input type="text" id="rgb" placeholder="rgb"> <img id="rgbError" class="hidden" src="data:image/svg+xml;utf8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIj48cGF0aCBkPSJNNTY5LjUxNyA0NDAuMDEzQzU4Ny45NzUgNDcyLjAwNyA1NjQuODA2IDUxMiA1MjcuOTQgNTEySDQ4LjA1NGMtMzYuOTM3IDAtNTkuOTk5LTQwLjA1NS00MS41NzctNzEuOTg3TDI0Ni40MjMgMjMuOTg1YzE4LjQ2Ny0zMi4wMDkgNjQuNzItMzEuOTUxIDgzLjE1NCAwbDIzOS45NCA0MTYuMDI4ek0yODggMzU0Yy0yNS40MDUgMC00NiAyMC41OTUtNDYgNDZzMjAuNTk1IDQ2IDQ2IDQ2IDQ2LTIwLjU5NSA0Ni00Ni0yMC41OTUtNDYtNDYtNDZ6bS00My42NzMtMTY1LjM0Nmw3LjQxOCAxMzZjLjM0NyA2LjM2NCA1LjYwOSAxMS4zNDYgMTEuOTgyIDExLjM0Nmg0OC41NDZjNi4zNzMgMCAxMS42MzUtNC45ODIgMTEuOTgyLTExLjM0Nmw3LjQxOC0xMzZjLjM3NS02Ljg3NC01LjA5OC0xMi42NTQtMTEuOTgyLTEyLjY1NGgtNjMuMzgzYy02Ljg4NCAwLTEyLjM1NiA1Ljc4LTExLjk4MSAxMi42NTR6Ii8+PC9zdmc+" /> </div> <script src="app.js"></script> </body> </html>
Я создал два текстовых поля с идентификаторами «hex» и «rgb» соответственно. Кроме того, каждое имеет иконку SVG для ошибки, которая по умолчанию имеет класс hidden.
Вот базовый макет, чтобы разметка выглядела немного лучше. Я определяю здесь два класса, .hidden и .dark. Первый используется для скрытия / отображения иконки ошибки SVG, а второй — для изменения цвета текста в зависимости от цвета фона. По умолчанию я установил для текста темный цвет (для яркого фона).
:root { --color: rgba(255,255,255,0.9); --tweet: white; } * { margin: 0; padding: 0; box-sizing: border-box; } ::placeholder { color: var(--color)!important; } body { padding: 50px; width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #28a745; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; } .head { position: absolute; top: 30px; text-align: center; color: var(--tweet); font-size: 3rem; border-bottom: 2px solid var(--tweet); } #content { display: block; } input { color: var(--color)!important; margin: 1rem 0; width: 400px; border: none; border-bottom: 1px solid var(--color); font-size: 2.5rem; background-color: transparent; } input:focus { outline: none; } .hidden { visibility: hidden; opacity: 0.8; } .dark { --color: rgba(0,0,0,0.75); --tweet: rgba(0,0,0,0.95); } img { width: 24px; } @media only screen and (max-width: 560px){ #content input { margin: 0.75rem 0; width: 90%; font-size: 1.875rem; } #content img { width: 16px; } .head { font-size: 2rem; } }
app.js
Здесь происходит магия. Я буду разбивать код на куски:
Во-первых, мы определяем переменные, которые связаны с полями ввода с id ‘hex’ и ‘rgb’. Далее, у нас есть функции для проверки правильности ввода Hex / RGB. Они используют базовую настройку регулярных выражений и возвращают логическое значение.
Здесь я создал функцию синтаксического анализа modifyHex, которая проверяет, имеет ли длина входного шестнадцатеричного символа 4 символа, то есть содержит ли «#»; и является ли она сокращением (например, #333) и заменяет «#» пустым символом. Затем он проверяет, составляет ли длина 3 символа, и расширяет ее до 6 символов (например, #123 = #112233).
Теперь мы определяем две функции, которые могут конвертировать hex в rgb и наоборот. Вот пошаговая разбивка для hexToRgb (этот код расширен, чтобы лучше объяснить, как работает процесс):
Определяем пустой массив для хранения результата.
Заменяем символ «#», если он существует, и, если длина не равна 6 (то есть сокращенная версия), вызываем указанную выше функцию modifyHex.
Преобразование hex в rgb работает путем преобразования шестнадцатеричного кода в код rgb (десятичная система). Каждые два символа в шестнадцатеричном коде представляют значение в цветовом коде rgb. Например, в #aabbcc красный — это (аа в десятичной системе), зеленый — это (bb в десятичной системе) и синий — это (cc в десятичной системе). Таким образом, в функции мы разделяем шестнадцатеричное значение, преобразуем его в десятичное с помощью parseInt, а затем сохраняем его в определенном массиве.
Наконец, мы возвращаем выходную строку.
Для функции rgbToHex:
Мы напрямую используем регулярное выражение для извлечения частей внутри круглых скобок, то есть rgb(123,21,24) вернет 123,21,24.
Затем мы используем функцию map для возврата нового массива, который преобразует число в шестнадцатеричноq системе счисления, а затем дополняет значение.
Позвольте мне объяснить эту часть. Когда мы используем регулярное выражение для соответствия частей внутри скобок, мы возвращаем данные типа «строка». Чтобы преобразовать их в Base 16, нам нужно использовать метод toString с параметром ’16′.
Метод toString применим только к числовым типам данных, поэтому мы используем сначала преобразование каждого элемента массива в число parseInt, затем используем toString(16) для преобразования его в шестнадцатеричную форму и, наконец, добавляем заполнение, чтобы его длина составляла ровно 2 символа. Заполнение необходимо, если у вас есть что-то вроде ’14′, которое вернет ‘e’. Но для шестнадцатеричного цветового кода требуется 2 символа для каждой части, поэтому необходимо заполнение — ’0e’.
Примечание: padStart — это функция ES8, которая может поддерживаться не во всех браузерах. Для простоты я не транспилировал код в ES5.
Наконец, мы возвращаем полученный массив, присоединяя его и переводя его в верхний регистр.
Эта функция используется для добавления этой маленькой метки ошибки с правой стороны поля ввода, если тип введенных данных неверен.
Она просто пропускает содержимое поля (hex.value и rgb.value) через соответствующие им функции проверки и использует возвращенное логическое значение для добавления / удаления класса .hidden.
Теперь мы определяем функцию, которая берет цвет фона, а затем определяет, является ли он темным или ярким (я взял этот код со StackOverflow). Он умножает отдельные значения цвета на некоторые вычисленные числа и возвращает «черный» или «белый». Затем я использую другую функцию для изменения цвета текста, добавляя / удаляя класс .dark.
Добавление прослушивателей событий:
Наконец, мы собираемся использовать все вышеперечисленные функции, добавив прослушиватели событий. Сначала мы добавляем событие keyup для поля ввода hex. Это событие срабатывает каждый раз при нажатии клавиши. Вот что делает эта функция:
Мы проверяем правильность введенного кода и расширяем его, если он сокращен.
Мы устанавливаем для цвета фона введенное значение.
Мы проверяем, является ли цвет светлым / темным, и соответственно меняем цвет текста.
Наконец, мы вызываем функцию convert и затем помещаем преобразованный цвет во поле RGB.
Другой прослушиватель событий, который мы использовали — blur . Он срабатывает каждый раз, когда с поля снимается фокус. Или, с точки зрения непрофессионала, каждый раз, когда вы кликаете / нажимаете за пределами элемента ввода, срабатывает blur.
Также мы проверяем, является ли шестнадцатеричный цвет действительным или нет, затем мы расширяем его, если он сокращенный, и, наконец, мы добавляем ‘#’, если он отсутствует. Обратите внимание, что мы проверяем, содержат ли индексы 0 и 1 «#». Это делается для того, чтобы функция не добавляла «#» дважды.
Далее мы добавляем тот же прослушиватель событий keyup для поля ввода rgb, и для него последовательности действий та же.
Наконец, мы добавляем прослушиватель событий keyup для всего документа, то есть он будет активирован для любого из двух элементов ввода. Внутри мы вызываем функцию errorMark, которая добавляет иконку ошибки, в случае возникновения ошибки, или удаляет ее, если все верно. Вот окончательный код app.js:
const hex = document.getElementById("hex"); const rgb = document.getElementById("rgb"); // Check Functions function checkHex(hex) { const hexRegex = /^[#]*([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i if (hexRegex.test(hex)) { return true; } } function checkRgb(rgb) { const rgbRegex = /([R][G][B][A]?[(]\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])(\s*,\s*((0\.[0-9]{1})|(1\.0)|(1)))?[)])/i if (rgbRegex.test(rgb)) { return true } } // Parse Function function modifyHex(hex) { if (hex.length == 4) { hex = hex.replace('#', ''); } if (hex.length == 3) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } return hex; } // Converting Functions function hexToRgb(hex) { let x = []; hex = hex.replace('#', '') if (hex.length != 6) { hex = modifyHex(hex) } x.push(parseInt(hex.slice(0, 2), 16)) x.push(parseInt(hex.slice(2, 4), 16)) x.push(parseInt(hex.slice(4, 6), 16)) return "rgb(" + x.toString() + ")" } function rgbToHex(rgb) { let y = rgb.match(/\d+/g).map(function(x) { return parseInt(x).toString(16).padStart(2, '0') }); return y.join('').toUpperCase() } // Helper Functions function addPound(x) { return '#' + x; } // Function to add cross mark on error values function errorMark() { if (checkHex(hex.value)) { document.getElementById('hexError').classList.add('hidden'); } else { document.getElementById('hexError').classList.remove('hidden'); } if (checkRgb(rgb.value)) { document.getElementById('rgbError').classList.add('hidden'); } else { document.getElementById('rgbError').classList.remove('hidden'); } } // Finding Contrast Ratio to change text color. Thanks https://stackoverflow.com/a/11868398/10796932 function getContrastYIQ(hexcolor) { if (checkHex(hexcolor)) { hexcolor = hexcolor.replace("#", '') } else { hexcolor = rgbToHex(hexcolor) } var r = parseInt(hexcolor.substr(0, 2), 16); var g = parseInt(hexcolor.substr(2, 2), 16); var b = parseInt(hexcolor.substr(4, 2), 16); var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; return (yiq >= 128) ? 'black' : 'white'; } function checkBG(str) { if (str == 'black') { document.body.classList.add('dark') } else if (str == 'white') { document.body.classList.remove('dark') } } // Adding Event Listeners hex.addEventListener('keyup', function() { let color = hex.value if (checkHex(color)) { color = modifyHex(color); document.body.style.backgroundColor = addPound(color); checkBG(getContrastYIQ(color)) rgb.value = hexToRgb(color); } }) hex.addEventListener('blur', function() { if (checkHex(hex.value)) { hex.value = modifyHex(hex.value) if (hex.value[1] != '#') { if (hex.value[0] != '#') { hex.value = addPound(hex.value); } } } }) rgb.addEventListener('keyup', function() { let color = rgb.value if (checkRgb(color)) { hex.value = color = addPound(rgbToHex(color)) document.body.style.backgroundColor = color; checkBG(getContrastYIQ(color)) } }) document.addEventListener('keyup', function() { errorMark(); })
Заключение
Вот и все! Я знаю, что этот код не идеален, его можно реорганизовать, но это только начало. Если вы хотите улучшить этот код, то можете открыть форк в моем репозитории github. Удачного кодирования!
Автор: Vaibhav Kandwal
Источник: https://medium.freecodecamp.org/
Редакция: Команда webformyself.