Эта статья посвящена тому, как я решил написать свой выбор цвета для сайта, потому что не устраивала кривая работа и тяжеловесность аналогов. Мой код не содержит ни одного плагина или библиотеки, поэтому он максимально простой и производительный.
Начнём с самого начала. Создаём базовую HTML-разметку:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<header>
<h1 id="title">Color Picker</h1>
</header>
</div>
<div id="colors-block"></div>
</body>
</html>
Далее надо вывести все цвета. Я решил выводить их на PHP, чтобы пользователь после открытия страницы уже видел палитру, а не ждал, пока это отрендерится у него на клиенте. Выводить решил в шестнадцатеричном варианте. Для этого делаем 6 вложенных циклов for и выводим блоки 1x1 px.
Код
<?php
$color = '';
for($i=0;$i<15;$i++) {
$a = $i;
switch($i) {
case 10:
$a = 'A';
break;
case 11:
$a = 'B';
break;
case 12:
$a = 'C';
break;
case 13:
$a = 'D';
break;
case 14:
$a = 'E';
break;
case 15:
$a = 'F';
break;
}
for($j=0;$j<15;$j++) {
$b = $j;
switch($j) {
case 10:
$b = 'A';
break;
case 11:
$b = 'B';
break;
case 12:
$b = 'C';
break;
case 13:
$b = 'D';
break;
case 14:
$b = 'E';
break;
case 15:
$b = 'F';
break;
}
for($k=0;$k<15;$k++) {
$c = $k;
switch($k) {
case 10:
$c = 'A';
break;
case 11:
$c = 'B';
break;
case 12:
$c = 'C';
break;
case 13:
$c = 'D';
break;
case 14:
$c = 'E';
break;
case 15:
$c = 'F';
break;
}
for($l=0;$l<15;$l++) {
$d = $l;
switch($l) {
case 10:
$d = 'A';
break;
case 11:
$d = 'B';
break;
case 12:
$d = 'C';
break;
case 13:
$d = 'D';
break;
case 14:
$d = 'E';
break;
case 15:
$d = 'F';
break;
}
for($m=0;$m<15;$m++) {
$e = $m;
switch($m) {
case 10:
$e = 'A';
break;
case 11:
$e = 'B';
break;
case 12:
$e = 'C';
break;
case 13:
$e = 'D';
break;
case 14:
$e = 'E';
break;
case 15:
$e = 'F';
break;
}
for($n=0;$n<15;$n++) {
$f = $n;
switch($n) {
case 10:
$f = 'A';
break;
case 11:
$f = 'B';
break;
case 12:
$f = 'C';
break;
case 13:
$f = 'D';
break;
case 14:
$f = 'E';
break;
case 15:
$f = 'F';
break;
}
$color = "#{$a}{$b}{$c}{$d}{$e}{$f}";
echo '<div class="color__item" style="width:1px; height:1px;background:'.$color.';"></div>';
$color = '';
}
}
}
}
}
}
Если i>=10 то заменяем на символ из шестнадцатеричной кодировки.
В итоге через пару минут ожидания я решил выключить пылесос, который почему-то лежал включенный. Но оказалось, что это не он, а кулер моего ноутбука. Я понял, что, видимо, вывожу сразу слишком много цветов, поэтому решил выводить только первые 10 000 цветов для тестирования. Получилась такая красота:
Неплохо, но попадать по цветам, слишком неудобно. Поэтому увеличим размеры "пикселей"
Отлично! Но есть одна проблема: здесь только синий цвет, но хотелось бы получить побольше. К сожалению, мой слабенький ноут не может отобразить всю палитру сразу, несмотря на то, что я не использую даже сторонних плагинов. Поэтому я решил выводить различные палитры для основных цветов в зависимости от GET-параметра. Для этого создаем меню:
<header>
<h1 id="title">Color Picker</h1>
<nav>
<ul>
<li><a href="?x=blue">Blue colors</a></li>
<li><a href="?x=green">Green colors</a></li>
<li><a href="?x=red">Red colors</a></li>
</ul>
</nav>
</header>
А в самом PHP и придумал хитрый способ чтобы переписывать нужны было как можно меньше. Теперь цвета выводятся вот так:
<?php
$x = $_GET['x'];
if ($x == 'red') {
$color = "#{$e}{$f}{$c}{$d}{$a}{$b}";
} elseif ($x == 'green') {
$color = "#{$a}{$b}{$e}{$f}{$c}{$d}";
} else {
$color = "#{$a}{$b}{$c}{$d}{$e}{$f}";
}
$q++;
if ($q <=10000) {
echo '<div class="color__item" style="width:2px; height:2px;background:'.$color.';"></div>';
$color = '';
}
Что получилось:
Остальные палитры доработаю чуть позже или можете доработать их сами!)
Теперь нам нужно непосредственно сделать выбор цвета и сохранение его в элемент формы. В HTML добавляем такой код:
<h3>Selected Color:</h3>
<div id="selected-color"></div>
<input type="hidden" id="color" name="color" value="rgb(255,255,255)">
А вот так выглядит JS:
document.querySelectorAll('.color__item').forEach((item, i, arr) => item.onclick = (e) => {document.querySelector('#selected-color').style.background = e.target.style.background; document.querySelector('#color').value = e.target.style.background});
Отлично! Теперь на все цвета вешается обработчик клика и выбранный цвет записывается в наш input[type='hidden'], который можно будет передать с остальной формой. Также мы показываем выбранный цвет пользователю
Безопасность
Не забудем и о безопасности. Так как название палитры передается как GET-параметр и обрабатывается нашим PHP, то есть вероятность XSS-инъекции! Чтобы защититься от инъекции, я позаимствовал код из этой статьи: https://habr.com/ru/post/470193/ Автор показал очень простой и эффективный способ защиты, так что не будем городить костыли и воспользуемся им. Код вставлять сюда не буду, т.к. он идентичен коду в той статье, поэтому не буду дублироваться.
Теперь при открытии страницы появляется ошибка: <b>Call to undefined function mysql_real_escape_string()</b>. Я сначала хотел просто удалить эту строку, но подумал, что если кто-то из вас будет пользоваться моим кодом, то наверняка у вас будет работа с базой данных, поэтому проблему нужно решить.
Я вспомнил, что mysql в PHP устарел, и надо использовать mysqli. Поэтому соответствующим образом исправил вызов функции.
Умная IDE подсказывает, что не хватает обязательного параметра. Поэтому вторым аргументом я просто добавил true. Я нередко видел, как вторым аргументом передают булево значение. Например, в json_decode()
Однако, это не сработало, появился warning, говорящий, что аргумент должен быть строкой. Пришлось обернуть true в кавычки, и это, конечно же, помогло.
$v = mysqli_real_escape_string( $v, 'true' );
Однако, теперь ругается на первый аргумент, говоря, что аргумент должен быть объектом mysqli(), поэтому вместо "$v" я передал "new mysqli()". Он опять начал ругаться на что-то, но у меня плохо с английским, и я не понял суть. Поэтому решил забить и просто закомментировать строку. Скорее всего это баг из-за того, что PHP8 вышел лишь недавно, и многое работает криво.
Зато от XSS мы теперь защищены!
Запоминание цветов
Наша палитра отлично работает, но хотелось бы иметь возможность "запомнить цвет" - чтобы пользователь в случае закрытия страницы смог быстро восстановить цвет, который он выбирал. Для этого добавляем следующий код:
<div id="save-color-block">
<button id="save-color__button">Запомнить мой цвет</button>
</div>
Как и говорил, у меня плохо с английский языком, и я не знаю как переводится "запоминать". Поэтому, написал по-русски (приношу извинения перед англоязычными пользователями моего кода (I am sorry)).
Теперь будем сохранять данные на сервере по клику на кнопку. Для этого пользователь должен будет ввести любой ключ по которому можно будет в будущем извлечь его цвет. Для ввода ключа воспользуемся функцией prompt(), т.к. самописные модальные окна - зло, и они пользователей бесят. Затем, для отправки на сервер будем использовать fetch - никаких jQuery, axios и т.п. Ведь наша задача сделать код простым и производительным, который поддерживать и использовать будет приятно.
Код получился вот таким:
document.querySelector('#save-color__button').onclick = () => {
const color = document.querySelector('#color').value;
const key = prompt('Write your key:');
const formData = new FormData();
formData.append('key', key);
formData.append('color', color);
fetch('save-color.php', {
method: 'POST',
body: formData
}).then((response) => {
if (response.status === 200) {
alert('success!');
} else {
alert('error!');
}
})
Теперь нам нужно создать файл "save-color.php". Код его будет крайне простым
<?php
$key = $_POST['key'];
$value = $_POST['color'];
file_put_contents($key.'.txt', $value);
Вот и всё! Теперь мы можем просто вбить в адресную строку mydomain.ru/{key}.txt и увидеть цвет, который мы выбирали!
Заключение
Вот так, буквально за пару часов мы реализовали свой функционал выбора цвета. Да, он ещё несовершенный, но каждый может править код под себя и использовать в своё удовольствие! Если эта статья не уйдёт в минус, то дальше я покажу, как очень просто можно найти все ключи ассоциативного массива с помощью простейшего перебора строк. А на этом всё. Пишите качественный и производительный код.
Ну и напоследок
/sarcasm