Сегодня сделаем интересную штуку — страницу, на которой будет сам появляться и исчезать текст, как будто его кто-то набирает. Это пригодится всем, кто выступает с презентациями и хочет показать основные мысли на экране. Вот как это выглядит:
Логика проекта
Проект будет состоять из трёх частей:
- Веб-страница, которую мы открываем в браузере и где появляется текст.
- Стили оформления — они будут отвечать за внешний вид текста и страницы в целом.
- Скрипт, который сделает всю магию, — он имитирует настоящий набор текста, как будто это делает живой человек.
Делать будем в той же последовательности: страница → стили → скрипт, чтобы лучше понять, что происходит на каждом этапе.
Создаём веб-страницу
Так как вся механика работы происходит в скрипте, то всё, что требуется от страницы, — выделить место для появления текста. Мы используем обычный тег <p>
— с ним мы сразу получаем автоматический перенос слов, если длина строки превышает ширину страницы.
Также сразу подключим файлы стилей и скриптов — их пока нет, но на работоспособность страницы это не повлияет.
<!DOCTYPE html>
<html lang="ru" >
<head>
<meta charset="UTF-8">
<title>Автотекст</title>
<!-- подключаем стили -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- текст будет появляться в этом блоке -->
<p></p>
<!-- подключаем скрипт -->
<script src="script.js"></script>
</body>
</html>
Сохраняем код в файле index.html и открываем файл в браузере. Так как контента на странице нет, то мы не увидим ничего, кроме белого фона. Исправим это в стилях.
Настраиваем стили
Сделаем стильно: белые буквы на чёрном фоне. Для этого создадим новый файл style.css, в котором пропишем:
- чёрный фон;
- белый текст;
- настроим отступы, чтобы текст не прилипал к краям экрана;
- вид и размер шрифта, чтобы он хорошо читался.
body {
/* цвет фона */
background: #000;
/* цвет текста */
color: #fff;
/* моноширинный шрифт */
font-family: monospace;
/* размер шрифта */
font-size: 34px;
/* отступы */
margin: 30px;
}
Для проверки добавим внутрь тега <p>
простой текст (и уберём его после проверки). Кажется, что стили работают как нужно, можно переходить к скрипту.
Пишем скрипт
Сначала подготовим текст, который будет появляться на экране. Для этого сделаем массив, где каждый элемент — новая мысль:
// текст, который будет появляться на экране
const text = ['Привет, это журнал «Код»! ',
'Одно из полезных применений нейросетей — распознавание изображений. Мы уже рассказывали, как нейронки распознают лица. ',
'Но с другими образами нейросети работают немного иначе — например, когда расшифровывают надписи или распознают различные объекты. ',
'Сегодня разбираемся, как они это делают. '
];
Идея такая:
- Берём первый элемент массива.
- Берём первую букву из текста этого элемента и добавляем её на экран.
- Переходим к следующему символу и делаем так до тех пор, пока не достигнем конца строки.
- Как только символы в первом элементе массива закончились — оставляем текст на экране на какое-то время и переходим ко второму элементу.
- Так проходим все элементы массива.
- В конце добавляем финальную надпись, которая остаётся на экране.
Для этого нам понадобятся переменные, чтобы следить, на какой позиции мы находимся:
// количество обработанных строк
let line = 0;
// текущий символ в строке
let count = 0;
// тут будет храниться то, что появится на экране
let result = '';
Теперь добавим две функции: одна нам нужна для паузы между мыслями на экране, а вторая будет отвечать за задержку между символами. Дело в том, что для естественного набора текста нам нужны разные интервалы между появлением новых букв. Для этого используем генератор случайных чисел — он каждый раз будет формировать новую задержку между символами в указанном нами диапазоне:
// функция для паузы, на вход она получает миллисекунды — сколько нужно подождать
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
// функция получения случайного целого числа
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
А теперь самое интересное: функция, которая обрабатывает массив с текстом и перебирает символ за символом. Центральная идея функции — обернуть её в таймер, который отвечает за вывод нового символа. Задержка таймера выбирается случайным образом, чтобы печать выглядела естественно.
Второй ключевой момент — рекурсивный вызов функции. Он нужен для того, чтобы задержки по таймеру срабатывали друг за другом, а не ждали, пока соберётся весь стек и выполнится всё и сразу.
Мы прокомментировали каждую строку кода, чтобы было проще разобраться, что происходит внутри:
// основная функция
function typeLine() {
// устанавливаем таймер
let interval = setTimeout(
() => {
// добавляем новый символ к строке для вывода
result += text[line][count]
// выводим текст на экран
document.querySelector('p').innerHTML =result +'|';
// увеличиваем счётчик символов
count++;
// если мы дошли до конца строки
if (count >= text[line].length) {
// обнуляем счётчик
count = 0;
// переходим к новой строке
line++;
// задерживаем текст на экране на 2 секунды
sleep(2000);
// очищаем текст на экране
document.querySelector('p').innerHTML = '';
// и в переменной
result = '';
// если обработали все линии
if (line == text.length) {
// останавливаем таймер
clearTimeout(interval);
// выводим финальный текст
document.querySelector('p').innerHTML ='Спасибо за внимание! ';
// заканчиваем работу функции
return true;
}
}
// рекурсивно вызываем функцию
typeLine();
// задаём в таймере время появления каждого нового символа
}, getRandomInt(getRandomInt(100*2.5)))
}
Сохраняем всё это в новом файле script.js и снова открываем страницу в браузере:
Посмотреть на работу автотекста на странице проекта
Что дальше
Сейчас у нас уже есть полноценный рабочий инструмент, но его можно доработать:
- сделать отдельный файл, где будут настройки внешнего вида и текст для вывода на экран;
- добавить реакцию на нажатия — сделать так, чтобы новая мысль появлялась только по нажатию клавиши;
- добавить навигацию, чтобы можно было в процессе вернуться к предыдущей или перейти к следующей мысли.
Сделаем это уже скоро в следующей версии проекта. Подпишитесь, чтобы не пропустить продолжение.
<!DOCTYPE html>
<html lang="ru" >
<head>
<meta charset="UTF-8">
<title>Автотекст</title>
<!-- подключаем стили -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- текст будет появляться в этом блоке -->
<p></p>
<!-- подключаем скрипт -->
<script src="script.js"></script>
</body>
</html>
body {
/* цвет фона */
background: #000;
/* цвет текста */
color: #fff;
/* моноширинный шрифт */
font-family: monospace;
/* размер шрифта */
font-size: 34px;
/* отступы */
margin: 30px;
}
// текст, который будет появляться на экране
const text = ['Привет, это журнал «Код»! ',
'Одно из полезных применений нейросетей — распознавание изображений. Мы уже рассказывали, как нейронки распознают лица. ',
'Но с другими образами нейросети работают немного иначе — например, когда расшифровывают надписи или распознают различные объекты. ',
'Сегодня разбираемся, как они это делают. '
];
// количество обработанных строк
let line = 0;
// текущий символ в строке
let count = 0;
// тут будет храниться то, что появится на экране
let result = '';
// функция для паузы, на вход она получает миллисекунды — сколько нужно подождать
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
// функция получения случайного целого числа
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
// основная функция
function typeLine() {
// устанавливаем таймер
let interval = setTimeout(
() => {
// добавляем новый символ к строке для вывода
result += text[line][count]
// выводим текст на экран
document.querySelector('p').innerHTML =result +'|';
// увеличиваем счётчик символов
count++;
// если мы дошли до конца строки
if (count >= text[line].length) {
// обнуляем счётчик
count = 0;
// переходим к новой строке
line++;
// задерживаем текст на экране на 2 секунды
sleep(2000);
// очищаем текст на экране
document.querySelector('p').innerHTML = '';
// и в переменной
result = '';
// если обработали все линии
if (line == text.length) {
// останавливаем таймер
clearTimeout(interval);
// выводим финальный текст
document.querySelector('p').innerHTML ='Спасибо за внимание! ';
// заканчиваем работу функции
return true;
}
}
// рекурсивно вызываем функцию
typeLine();
// задаём в таймере время появления каждого нового символа
}, getRandomInt(getRandomInt(100*2.5)))
}
// запускаем основную функцию
typeLine();