Как реализовать функцию чата в реальном времени без кода JS❓

CSS
Как реализовать функцию чата в реальном времени без кода JS❓

введение

Некоторое время назад я видел на гитхабе очень "хитрый" проект: реализовать чат-приложение на чистом CSS (то есть без JavaScript) -css-only-chat. То есть эффект, показанный на рисунке ниже.

На наш взгляд, реализовать простое чат-приложение (обмен сообщениями и многостраничная синхронизация) несложно — это с помощью JavaScript. И если вы можете использовать только CSS без внешнего кода JavaScript, сможете ли вы это сделать?

Оригинал представляет собой бэкенд, написанный на Ruby. Возможно, вы мало знаете о Ruby, поэтому я реализовал версию с NodeJS по оригинальной идее автора.css-only-chat-node, который может быть легче читать для всех.

1. Какую проблему мы пытаемся решить?

В первую очередь следует подчеркнуть, что код на стороне сервера все равно должен быть написан, и эта часть явно не может быть CSS. Таким образом, «чистый CSS» здесь в основном относится к использованию только CSS на стороне браузера.

Вспомните, если вы используете JavaScript для реализации функции чата, показанной на изображении выше, какие проблемы необходимо решить?

  • Во-первых, вам нужно добавить кнопкуclickМониторинг событий, включая нажатие кнопки персонажа и нажатие кнопки отправки;
  • Во-вторых, после нажатия соответствующей кнопки информация должна быть отправлена ​​на серверный сервис через Ajax;
  • Кроме того, для обеспечения отображения сообщений в реальном времени обычно устанавливается соединение WebSocket;
  • Наконец, для сообщений из внутренней синхронизации мы будем использовать DOM API на стороне браузера, чтобы изменить содержимое DOM и отобразить записи сообщений.

Операции, связанные с JavaScript, в основном состоят из четырех вышеперечисленных. Однако теперь мы можем использовать только CSS, как мы можем реализовать вышеуказанные операции?

2. Trick Time

2.1.Решаем проблему "мониторинга кликов"

В JavaScript это может сделать одна строка кода:

document.getElementById('btn').addEventListener('click', function () {
    // ……
});

В CSS на самом деле есть псевдокласс, который может нам помочь, а именно:active. Он может выбирать активные элементы, и когда мы нажимаем на элемент, он становится активным.

Итак, для 26 писем на анимации выше (плюс кнопка отправки) можно назначить разныеclassname, а затем установите селектор псевдокласса так, чтобы при нажатии кнопки, соответствующей этой букве, срабатывало правило CSS. Например, для символа «а» можно задать следующие правила «захвата» кликов:

.btn_a:active {
    /* …… */ 
}

2.2. Отправка запроса

Если у вас есть помощь JavaScript, вам нужно использовать XHR только для отправки запроса, что очень удобно. А для CSS есть ли способ отправить запрос?

можно использоватьbackground-imageатрибут, укажите его как URL-адрес, чтобы внешний интерфейс инициировал запрос фонового изображения на сервер. почему его можно использоватьbackground-imageсвойство также потому, что: браузер не будет запускаться до тех пор, пока правило селектора CSS не будет фактически применено к элементу DOM.background-imageзапрос. Например, следующее правило:

.btn_a:active {
    background-image: url('/keys/a');
}

Браузер сделает запрос к серверу только после того, как будет нажата буква «а»./keys/aЭта картинка". На стороне сервера, оценивая URL-адрес, вы можете узнать, какой символ был нажат во внешнем интерфейсе. Например, для кнопки «b» будут следующие правила:

.btn_b:active {
    background-image: url('/keys/b');
}

Это эквивалентно реализации URL (/keys/aа также/keys/b) в "параметрах передачи".

2.3 Отображение сообщений в реальном времени

Для отображения сообщений в режиме реального времени ядро ​​будет использовать технологию под названием «проталкивание сервером». Среди наиболее распространенных методов:

  • Используйте JavaScript для установки соединения WebSocket с сервером
  • Используйте JavaScript для создания таймера и регулярного опроса запросов.
  • Использование JavaScript и взаимодействия на стороне сервера для реализации длительного опроса

Но ни один из этих способов не может обойти JavaScript, который явно не соответствует нашим требованиям. На самом деле есть еще один способ, я"Принципы и примеры различных технологий "Server Push"Это также упоминается в режиме длинного потока соединения (потока) на основе iframe.

Здесь мы в основном опираемся на модель «длинного потока соединений». Пусть наша страница всегда будет в незагруженном состоянии. Однако, поскольку заголовок запроса содержитTransfer-Encoding: chunked, который сообщает браузеру, что, хотя страница еще не завершена, вы можете начать ее отрисовку. Именно потому, что ответ на запрос никогда не заканчивается, поэтому мы можем продолжать писать в него новый контент, чтобы обновлять отображение страницы.

Это также очень просто реализовать.http.ServerResponseСам класс наследуется отStream, поэтому вызывайте только тогда, когда содержимое страницы необходимо обновить..write()метод. Например, следующий код может динамически добавлять строку «hello» на страницу каждые 2 секунды без взаимодействия со стороны браузера (и без необходимости писать код JavaScript):

const http = require('http');
http.createServer((req, res) => {
    res.setHeader('connection', 'keep-alive');
    res.setHeader('content-type', 'text/html; charset=utf-8');
    res.statusCode = 200;
    res.write('I will update by myself');

    setInterval(() => res.write('<br>hello'), 2000);
}).listen(8085);

2.4. Изменить информацию о странице

В предыдущем разделе мы смогли динамически изменять содержимое страницы без JavaScript с помощью метода Stream. Но если вы будете осторожны, вы обнаружите, что этот метод может только постоянно «добавлять» содержимое. В нашем случае это больше похоже на возможность динамического изменения текста в DOM, например, текст за «Текущим сообщением» будет изменяться при нажатии разных кнопок.

На самом деле здесь есть очень "хитрый" способ. Часть ниже (назовем ее ChatPanel)

На самом деле, каждый раз, когда мы звонимres.write()вернет совершенно новый HTML-фрагмент ChatPanel. В то же время будет<style>элемент, установите для предыдущей панели ChatPanel значениеdisplay: none. Таким образом, содержимое исходной панели ChatPanel выглядит обновленным, но на самом деле оно добавляет новое, скрывая предыдущую панель ChatPanel.

2.5. Нажатие кнопки «Дублировать»

Пока что основная схема есть, но есть одна важная проблема:

в правилах CSSbackground-imageЗапрос будет сделан только при первом применении к элементу, и после этого никаких дальнейших запросов к серверу не будет. То есть с помощью

.btn_a:active {
    background-image: url('/keys/a');
}

С этим правилом после однократного нажатия кнопки «а» на следующий клик не будет ответа — то есть бэкэнд не получит запрос.

Есть способ решить эту проблему. Вы можете применить новый набор правил стиля для каждой кнопки символа и установить новый набор правил стиля в новой ChatPanel, возвращаемой каждый раз (что такое ChatPanel, мы упоминали в предыдущем разделе, если вы забыли, вы можете вернуться и посмотреть на него ) URL фонового изображения. Например, после того, как мы нажмем «h» в первый раз, кнопка «a» в возвращенной ChatPanelclassnameЭто станетbtn_h_aСоответствующие правила CSS изменены:

.btn_h_a:active {
    background-image: url('/keys/h_a');
}

После повторного нажатия «i» правило стиля соответствующей кнопки в ChatPanel изменяется на:

.btn_hi_a:active {
    background-image: url('/keys/hi_a');
}

2.6. Хранение

Чтобы иметь возможность сохранять неотправленное содержимое (введенное до нажатия кнопки отправки) и синхронизировать исторические сообщения, должно быть место для хранения пользовательского ввода. Мы также устанавливаем уникальный идентификатор пользователя для каждого соединения. Использовал Redis в ванильном css-only-chat. В css-only-chat-node я напрямую сохраняю его в переменной памяти времени выполнения для простоты.

3. Наконец

Некоторые друзья могут спросить, имеет ли эта DEMO какую-либо практическую ценность? Можно ли превратить его в полезный инструмент для чата?

Ну, на самом деле я не думаю, что это очень полезно. Но это нормально, чтобы понять некоторые из «узлов знаний», связанных с этим. Мы сталкиваемся с таким количеством неинтересных потребностей каждый день, и время от времени просмотр таких «интересных» проектов может быть расценен как расслабляющий.

Наконец, если вы хотите увидеть конкретный эффект запуска или узнать подробности кода, вы можете посмотреть здесь:

  • css-only-chat-node: поскольку исходная версия написана на Ruby, версия NodeJS реализована для всеобщего обозрения.
  • css-only-chat: Оригинальный репозиторий для css-only-chat, реализованный на Ruby.

Просто получайте удовольствие!