Задача
СкопированоНередко разработчик хочет знать число символов, которые пользователь вводит. Например, так можно сообщать количество доступных знаков.
Создадим такой счётчик без лишней нагрузки браузера (и человека).
Готовое решение
СкопированоВ самой простой версии нам нужно поле ввода и вывода:
<input> <output>0</output>
<input> <output>0</output>
Сам счётчик выглядит так:
const input = document.querySelector('input') const output = document.querySelector('output') input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length })
const input = document.querySelector('input') const output = document.querySelector('output') input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length })
Попробуйте код в демо ниже:
Разбор решения
СкопированоВ примере счётчик нужен для удобства пользователя, чтобы он видел число символов и не вспоминал про ограничение в семь букв.
Разметка
СкопированоДва блока, один с текстом загадки, другой с интерактивными элементами.
В качестве инструмента ввода у нас будет <input>
, а счётчик символов положим в <output>
. Последний удобно использовать для вывода результатов вычислений, а ещё он хорошо дружит со скринридерами:
<div class="riddle"> <p>Вокруг снег, да лес не белый.</p> <p>А какой?</p></div><div class="solution"> <label for="answer">Угадайте цвет:</label> <input id="answer" placeholder="Семь букв" autocomplete="off"> <output>0</output></div>
<div class="riddle"> <p>Вокруг снег, да лес не белый.</p> <p>А какой?</p> </div> <div class="solution"> <label for="answer">Угадайте цвет:</label> <input id="answer" placeholder="Семь букв" autocomplete="off"> <output>0</output> </div>
Стили
СкопированоДва блока разместим друг под другом с помощью flex
:
body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 30px;}
body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 30px; }
Блок с подсказкой визуально выделим цветом и размером:
.riddle { width: 55%; padding: 55px 40px; background-color: #C56FFF;}.riddle p { color: #000000; font-size: 24px; text-align: center;}
.riddle { width: 55%; padding: 55px 40px; background-color: #C56FFF; } .riddle p { color: #000000; font-size: 24px; text-align: center; }
А блок с решением подготовим к выводу эмодзи. Они понадобятся для наглядности результатов:
.solution { width: 410px;}.solution::after { content: var(--solution-emoji);}
.solution { width: 410px; } .solution::after { content: var(--solution-emoji); }
Лейбл и поле ввода:
label { margin-right: 15px; font-size: 24px; font-weight: 500; line-height: 1;}input { width: 150px; border: 1px solid #FFFFFF; border-radius: 6px; padding: 10px 15px; background-color: transparent; color: #FFFFFF; font-size: 18px; font-weight: 300; font-family: inherit; -webkit-appearance: none; appearance: none;}input:focus { border-color: #C56FFF; outline: none;}
label { margin-right: 15px; font-size: 24px; font-weight: 500; line-height: 1; } input { width: 150px; border: 1px solid #FFFFFF; border-radius: 6px; padding: 10px 15px; background-color: transparent; color: #FFFFFF; font-size: 18px; font-weight: 300; font-family: inherit; -webkit-appearance: none; appearance: none; } input:focus { border-color: #C56FFF; outline: none; }
Счётчик стилизуем в виде небольшого квадратика со сглаженными углами:
output { display: inline-block; width: 30px; border-radius: 5px; background-color: #C56FFF; text-align: center; margin-left: 10px;}
output { display: inline-block; width: 30px; border-radius: 5px; background-color: #C56FFF; text-align: center; margin-left: 10px; }
JavaScript
СкопированоСначала получим блок с результатами для добавления эмодзи. Затем поля ввода и вывода, а также объявим переменную с длиной правильного ответа:
const solution = document.querySelector('.solution')const input = solution.querySelector('input')const output = solution.querySelector('output')const ANSWER_LENGTH = 7
const solution = document.querySelector('.solution') const input = solution.querySelector('input') const output = solution.querySelector('output') const ANSWER_LENGTH = 7
На поле ввода повесим обработчик событий и подпишемся на событие input
. Оно случится, когда пользователь введёт какие-то данные:
input.addEventListener('input', function () {})
input.addEventListener('input', function () {})
Внутри разместим сам счётчик. С помощью this
мы получим доступ к объекту события, в нашем случае к input
. Его значение получим с помощью метода value
, это и будут символы, которые пользователь введёт. Чтобы избежать подсчёта начальных и концевых пробелов, используем функцию trim
.
Методом length
посчитаем их количество и прибавим к нулю, а с помощью метода text
разместим число в поле вывода:
input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length})
input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length })
Для красоты можно добавить изменение стилей на случай правильного ответа или превышения числа символов:
if (str.length > ANSWER_LENGTH) { output.style.backgroundColor = '#a52a2a' solution.style.setProperty('--solution-emoji', '"❌"')} else { output.style.backgroundColor = '#C56FFF' solution.style.setProperty('--solution-emoji', '"🔄"')}if (/^зел[её]ный$/i.test(str)) { output.style.backgroundColor = '#41E847' solution.style.setProperty('--solution-emoji', '"✅"')}
if (str.length > ANSWER_LENGTH) { output.style.backgroundColor = '#a52a2a' solution.style.setProperty('--solution-emoji', '"❌"') } else { output.style.backgroundColor = '#C56FFF' solution.style.setProperty('--solution-emoji', '"🔄"') } if (/^зел[её]ный$/i.test(str)) { output.style.backgroundColor = '#41E847' solution.style.setProperty('--solution-emoji', '"✅"') }
Когда символов будет больше семи, мы окрасим счётчик в красный и добавим крестик, а если меньше, то вернём голубой цвет и оставим значок загрузки. В случае правильного ответа окрасим счётчик в зелёный 👽 и добавим галочку.
А ещё, чтобы слово «зелёный» проходило проверку в любой форме, используем регулярное выражение и метод test
, который возвращает true
при совпадении либо false
.
Посчитать символы можно и в <textarea>
, метод работы тот же:
textarea.addEventListener('input', function () { output.textContent = 0 + this.value.length})
textarea.addEventListener('input', function () { output.textContent = 0 + this.value.length })
Финальный код
Скопировано<div class="riddle"> <p>Вокруг снег, да лес не белый.</p> <p>А какой?</p></div><div class="solution"> <label for="answer">Угадайте цвет:</label> <input id="answer" placeholder="Семь букв" autocomplete="off"> <output>0</output></div>
<div class="riddle"> <p>Вокруг снег, да лес не белый.</p> <p>А какой?</p> </div> <div class="solution"> <label for="answer">Угадайте цвет:</label> <input id="answer" placeholder="Семь букв" autocomplete="off"> <output>0</output> </div>
body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 30px;}.riddle { width: 55%; padding: 55px 40px; background-color: #C56FFF;}.riddle p { color: #000000; font-size: 24px; text-align: center;}.solution { width: 410px;}.solution::after { content: var(--solution-emoji);}label { margin-right: 15px; font-size: 24px; font-weight: 500; line-height: 1;}input { width: 150px; border: 1px solid #FFFFFF; border-radius: 6px; padding: 10px 15px; background-color: transparent; color: #FFFFFF; font-size: 18px; font-weight: 300; font-family: inherit; -webkit-appearance: none; appearance: none;}input:focus { border-color: #C56FFF; outline: none;}output { display: inline-block; width: 30px; border-radius: 5px; background-color: #C56FFF; text-align: center; margin-left: 10px;}
body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 30px; } .riddle { width: 55%; padding: 55px 40px; background-color: #C56FFF; } .riddle p { color: #000000; font-size: 24px; text-align: center; } .solution { width: 410px; } .solution::after { content: var(--solution-emoji); } label { margin-right: 15px; font-size: 24px; font-weight: 500; line-height: 1; } input { width: 150px; border: 1px solid #FFFFFF; border-radius: 6px; padding: 10px 15px; background-color: transparent; color: #FFFFFF; font-size: 18px; font-weight: 300; font-family: inherit; -webkit-appearance: none; appearance: none; } input:focus { border-color: #C56FFF; outline: none; } output { display: inline-block; width: 30px; border-radius: 5px; background-color: #C56FFF; text-align: center; margin-left: 10px; }
const solution = document.querySelector('.solution')const input = solution.querySelector('input')const output = solution.querySelector('output')const ANSWER_LENGTH = 7input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length if (str.length > ANSWER_LENGTH) { output.style.backgroundColor = '#a52a2a' solution.style.setProperty('--solution-emoji', '"❌"') } else { output.style.backgroundColor = '#C56FFF' solution.style.setProperty('--solution-emoji', '"🔄"') } if (/^зел[её]ный$/i.test(str)) { output.style.backgroundColor = '#41E847' solution.style.setProperty('--solution-emoji', '"✅"') }})
const solution = document.querySelector('.solution') const input = solution.querySelector('input') const output = solution.querySelector('output') const ANSWER_LENGTH = 7 input.addEventListener('input', function () { const str = this.value.trim() output.textContent = 0 + str.length if (str.length > ANSWER_LENGTH) { output.style.backgroundColor = '#a52a2a' solution.style.setProperty('--solution-emoji', '"❌"') } else { output.style.backgroundColor = '#C56FFF' solution.style.setProperty('--solution-emoji', '"🔄"') } if (/^зел[её]ный$/i.test(str)) { output.style.backgroundColor = '#41E847' solution.style.setProperty('--solution-emoji', '"✅"') } })