Занурення в JavaScript: Як створити перетворювач кольорів Hex2RGB

Оновлення (23.07.2019): Я виправив кілька граматичних помилок і трохи змінив код app.js, видаливши функцію checkBG.

У цій статті ми створимо веб-програму, яка перетворює кольорові коди між шістнадцятковою формою та формою RGB.

Демо-версію можна знайти тут, а вихідний код - тут.

Структура проекту:

Структура проекту досить проста.

  1. index.html : Містить структуру програми.
  2. style.css : Стилістику сторінки.
  3. app.js : Містить весь магічний код.

Ідея:

Ось список речей, які я хотів виконати цим додатком:

  1. Щоразу, коли щось вводиться в текстове поле для шістнадцяткового тексту, програма повинна перевіряти, чи правильний колір. Якщо це так, перетворіть його у RGB, встановіть як фон, а потім помістіть значення RGB у текстове поле RGB і навпаки.
  2. Якщо в текстове поле введено короткий шістнадцятковий колірний код, розгорніть його, коли текстове поле втратить фокус (користувач клацає поза текстовою областю).
  3. Автоматично додавати символ "#" до шістнадцяткового вводу.

Давайте почнемо!

index.html

      Hex to RGB Converter HEX <--> RGB 

Ми створили два текстових поля з ідентифікаторами 'hex' та 'rgb' відповідно. Поруч з кожним входом є піктограма SVG для помилок, яка за замовчуванням має клас прихованих.

style.css

: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; } img { width: 24px; } .hidden { visibility: hidden; opacity: 0.8; } .dark { --color: rgba(0,0,0,0.75); --tweet: rgba(0,0,0,0.95); } @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; } } 

Ось базовий макет, щоб розмітка виглядала дещо кращою. Ми визначили тут два класи, .hiddenі .dark..hiddenвикористовується, щоб приховати / показати піктограму SVG про помилку і .darkполягає у зміні кольору тексту на основі кольору фону. За замовчуванням я встановив для тексту темний колір (для яскравих фонів).

app.js

Ось магічна частина. Я буду розбивати код на шматки:

По-перше, ми визначили змінні, які націлені на вхідні дані з ідентифікаторами 'hex' та 'rgb'. Далі ми маємо функції, які перевіряють, чи введений Hex / RGB дійсний чи ні. Вони використовують базове налаштування регулярного виразу і повертають логічне значення. Якщо вони вас залякують, я рекомендую вам спробувати цей RegexTutorial.

Тут ми написали функцію синтаксичного аналізу, modifyHexяка перевіряє, чи вхідний шістнадцятковий код має 4 символи; тобто містить "#" і є скороченням (наприклад, # 333) і замінює "#" порожнім символом. Потім він перевіряє, чи довжина зараз дорівнює 3, і розширює його до 6 символів (наприклад, # 123 = # 112233).

Ми визначили дві функції, які перетворюють hex у rgb і навпаки. Ось покрокова розбивка для hexToRgb(Цей процес написаний у розширеній формі для кращого розуміння):

  1. Визначте порожній масив для зберігання результату.
  2. Замініть символ "#", якщо він існує, і якщо довжина не дорівнює 6 (тобто скорочена версія), зателефонуйте вищезазначеній modifyHexфункції та розгорніть її.
  3. Дуже елементарно hex в rgb працює, перетворюючи шістнадцятковий код (в основі 16) в код rgb (в основі 10). Кожні два символи в шістнадцятковому коді представляють значення в коді кольору rgb. Наприклад, у #aabbcc червоний - це (aa до основи 10), зелений - (bb до основи 10), а синій - (cc до основи 10). Отже, у функції ми нарізаємо шістнадцяткове значення, перетворюємо його на базу 10 за допомогою parseInt, а потім зберігаємо в визначеному масиві.
  4. Нарешті, ми повертаємо вихідний рядок, приєднуючись до наведеного вище масиву.

Для rgbToHexфункції (це написано з коротшою логікою):

  1. Ми безпосередньо використовуємо регулярний вираз для вилучення лише числових значень - тобто rgb (123,21,24) поверне 123,21,24.
  2. Далі ми використовуємо функцію map для повернення нового масиву, який перетворює число на базу 16, а потім додає значення.

Звичайний вираз, який ми використовували вище, повертає дані типу 'рядок'. Щоб перетворити його на базу 16, нам потрібно скористатися toString()  методом із параметром "16".

Тепер toString()метод застосовується лише до числових типів даних, тому ми parseIntспочатку перетворюємо кожен елемент масиву в число, потім використовуємо toString(16)для перетворення його в шістнадцяткову форму, а потім, нарешті, додаємо відступ, щоб зробити його рівно 2 символи. Заповнення необхідне, якщо у вас є щось на зразок "14", яке ви хочете перетворити в шістнадцяткове, воно поверне "e". Але шістнадцятковий колірний код потребує 2 символів для кожної частини, тому необхідне заповнення, що робить його "0e".

Примітка: padStartце функція ES8, яка може підтримуватися не у всіх браузерах. Щоб спростити цей підручник, я не переклав його на ES5.

3. Нарешті, ми повертаємо отриманий масив, об’єднуючи його та перетворюючи у верхній регістр.

errorMark()Функція використовується, щоб показати або приховати піктограму SVG про помилку. Він просто передає вміст вводу ( hex.valueі rgb.value) через відповідні функції перевірки та використовує повернене логічне значення для додавання / видалення .hiddenкласу.

Тепер ми визначаємо функцію, яка приймає колір фону, а потім визначає, темний він чи яскравий (я отримав цей код від StackOverflow). Він множить окремі значення кольору з деякими обчисленими числами і повертає "чорний" або "білий". Потім я використовую іншу функцію для зміни кольору тексту, додаючи / видаляючи .darkклас.

Додавання слухачів подій:

Нарешті, ми підключаємо всі функції, додаючи прослуховувачі подій.

По-перше, ми додаємо keyupподію до hexвхідних даних. Ця подія спрацьовує кожного разу, коли відпускається ключ. Ось розподіл процесу:

  1. Перевірте правильність введеного коду та розширте його, якщо це скорочення.
  2. Встановіть колір фону тіла на вхідне значення.
  3. Перевірте кольорову контрастність і відповідно змініть колір тексту.
  4. Викличте функцію перетворення та помістіть перетворений колір у поле введення 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 //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) ? document.body.classList.add('dark') : 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); 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; getContrastYIQ(color) } }) document.addEventListener('keyup', function() { errorMark(); })

Висновок

Ось тобі! Я знаю, що код не ідеальний і може бути реконструйований, але привіт, це лише початок. Якщо ви хочете вдосконалити цей код, ви можете продовжити і відкрити PR на моєму репозиторії github.

Щасливого кодування!