Создайте мощный веб-чат с машинописным текстом

Vue.js
Создайте мощный веб-чат с машинописным текстом

Введение

😛 В свободное время я хотел создать чат для закрепления навыков фронтенда, поэтому 24 июня 2020 года я начал разработку чата Astro.
😈 Проект разрабатывается с полным машинописным текстом, который закладывает основу для будущих итераций функционала. Конечно, я тоже очень люблю машинопись.

Интерфейс проекта

Функции

  • Мобильная совместимость
  • Изменение информации о пользователе (аватар/имя пользователя/пароль)
  • Групповой чат/приватный чат
  • Создать группу/присоединиться к группе/покинуть группу/группу нечеткого поиска
  • Добавить друга/удалить друга/пользователя нечеткого поиска
  • Пейджинг сообщений
  • эмодзи
  • Отправка изображения/предварительный просмотр изображения
  • Онлайн-подсчет людей
  • пользовательский фон
  • Напоминание о повторном подключении

Обзор технологии

  • Typescript: надмножество JavaScript, его самым большим преимуществом является предоставление системы типов и повышение удобочитаемости и ремонтопригодности кода.
  • Vue2.6.x: Фронтенд прогрессивный фреймворк.
  • Socket/io: Связь в режиме реального времени, сторонняя библиотека websocket.
  • Vuex: шаблон управления состоянием, разработанный специально для приложений Vue.js.
  • Nestjs: это эффективная и масштабируемая среда серверных приложений Node.js, написанная на основе TypeScript и объединенная с родственными концепциями OOP1, FP2 и FRP3.
  • Typeorm: поддерживает новейшие функции JavaScript и предоставляет дополнительные функции, которые помогут вам разработать любое приложение, использующее базу данных.
  • ES6+: использование синтаксиса ES6+, стрелочных функций, синтаксиса async/await и т. д. очень полезно.
  • SASS(SCSS): Используя SCSS в качестве языка предварительной обработки CSS, вы можете использовать наиболее эффективный способ создания сложных дизайнов с небольшим объемом кода.

Зачем использовать машинопись

  1. Поскольку в чатах используются более сложные структуры данных, использование машинописного текста позволяет избежать многих низкоуровневых ошибок благодаря напоминаниям компилятора в процессе разработки.
  2. С определением типа машинописного текста структура данных системы становится ясной с первого взгляда, а удобство сопровождения и читабельность кода значительно улучшаются.

Структура таблицы базы данных

В базе данных используются шесть таблиц, которые

  • пользовательская таблица пользователей
  • Групповая группа
  • промежуточная таблица user_group user_group
  • group_message таблица групповых сообщений
  • user_friend user_friend промежуточная таблица
  • friend_message таблица сообщений приватного чата

Промежуточная таблица используется для установления связи между группой/другом и пользователем. Ниже представлена ​​ментальная карта, которую я нарисовал. Думаю, каждый сможет понять тайну, прочитав ее.

Логика создания WebSocket

Создание пользовательской комнаты

Каждый пользователь, который входит в комнату чата, автоматически присоединится к комнате WebSocket, названной public, и комнате WebSocket, названной в честь идентификатора пользователя.Комната пользователя создана, чтобы облегчить системе трансляцию событий индивидуально для пользователей. Если вы не понимаете концепции комнаты, вы можете подумать, что только люди, находящиеся в комнате, могут принимать трансляции в комнате.Для получения дополнительной информации посетите официальный сайт socket.io.

Создание группового чата

С groupId в качестве имени комнаты WebSocket каждый раз, когда новый пользователь присоединяется к группе, событие присоединения пользователя будет транслироваться в комнате группы с подробной информацией о новом пользователе, а затем другие пользователи будут хранить информацию о новом пользователе. Когда новый пользователь отправляет сообщение, другие пользователи могут найти подробную информацию о соответствующем пользователе через идентификатор пользователя сообщения после получения сообщения. Это гарантирует, что другие пользователи смогут быстро узнать владельца сообщения после его отправки.

Создайте приватный чат

Всякий раз, когда инициируется запрос на добавление друга, строка, объединенная userId пользователя и userId друга, будет использоваться в качестве имени комнаты WebSocket, тем самым создавая приватную комнату чата.

Бэкэнд-архитектура

Серверная часть используетnesjs, фреймворк node.js, который быстро развивался в последние годы. Преимуществ уnesjs много, перечислю только следующие:

  1. Построен на TypeScript и совместим с простым ES6.
  2. Внедрение зависимостей NestJS и идея модульности делают структуру кода понятной и простой в обслуживании.
  3. Пакет Nestjs @nestjs/websockets инкапсулирует обработку событий WebSocket, что дает большие преимущества при разработке чатов.

Ниже приведен код внутренней логики.

  1. Используйте nestjs для установки соединения WebSocket
// chat.gateway.ts
@WebSocketGateway()
export class ChatGateway {
  // socket连接钩子
  async handleConnection(client: Socket): Promise<string> {
    let userRoom = client.handshake.query.userId;
    // 连接默认加入public房间
    client.join('public');
    // 用户独有消息房间 根据userId
    if(userRoom) {
      client.join(userRoom);
    }
    return '连接成功'
  }
}
  1. Инкапсулирует глобальное ПО промежуточного слоя для облегчения отладки во время разработки.
// middleware.js
export function logger(req, res, next) {
  const { method, path } = req;
  console.log(`${method} ${path}`);
  next();
};

// main.js 
使用全局中间件
app.use(logger)
  1. Конфигурация статических ресурсов для nestjs
// main.js
配置静态资源
app.useStaticAssets(join(__dirname, '../public/', 'static'), {
  prefix: '/static/', 
});
  1. Пользовательский фильтр исключений Nestjs
// http-exception.filter.ts
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    const status = exception.getStatus();
    const exceptionRes: any = exception.getResponse();
    const {
      error,
      message,
    } = exceptionRes;
    // 以下格式将在请求错误时返回给前端
    response.status(status).json({
      status,
      timestamp: new Date().toISOString(),
      path: request.url,
      error,
      message,
    });
  }
}

Интерфейсная архитектура

инициализация страницы

Инициализация вызовет функцию соединения WebSocket, а затем получит всю информацию о группе и всю информацию о друзьях пользователя, а затем присоединится к соответствующей комнате через правила установления связи WebSocket, а затем использует vuex для распространения последних данных.

обработка данных

групповой тип данных

// 群组
interface Group {
  groupId: string;
  userId: string; // 群主id
  groupName: string;
  notice: string;
  messages: GroupMessage[];
  createTime: number;
}

Тип данных друзей

// 好友
interface Friend {
  userId: string;
  username: string;
  avatar: string;
  role?: string;
  tag?: string;
  messages: FriendMessage[];
  createTime: number;
}

Раньше я использовал структуру массива объектов [ друг1 , друг2 ... ] для управления всеми данными группы/друга, но когда объем данных велик, запросы и обновление данных группы/друга становятся очень дорогими. Каждый раз, когда меняется имя друга или меняется аватар, необходимо пройтись по массиву, чтобы обновить соответствующую информацию.
Позже я использовал структуру объекта для оптимизации кода чата. Я использую сбор объектов для управления информацией о группе/друге.Ключом сбора является groupId/userId, а значением являются данные соответствующей группы/друга.Структура выглядит следующим образом

gather = {
 'userId': {
   userId: 'userId'
   username: 'xxx'
   messages: [];
   ...
 }
}

Каждая группа и пользователь имеют уникальный идентификатор, поэтому не нужно беспокоиться о дублировании. После использования такой структуры очень легко обновить данные, достаточно получить идентификатор, который необходимо обновить, а затем напрямую перезаписать значение, соответствующее collect.id.

vuex

Комната чата включает в себя мгновенное обновление данных и синхронизацию данных каждого компонента vue Обработка таких бизнес-сценариев — сильная сторона vuex. Я написал функцию установления соединения WebSocket в действии vuex, и функция соединения вызывается после успешного входа пользователя.Ниже приведен упрощенный код.

// actions.ts
const actions: ActionTree<ChatState, RootState> = {
  // 初始化WebSocket
  async connectSocket({commit, state, dispatch, rootState}, callback) {
    // WebSocket连接建立
    socket.on('connect', async () => {
      // 订阅群消息时间
      socket.on('groupMessage', (res: any) => {
        console.log('on groupMessage', res)
        if (!res.code) {
          // 对群消息进行处理
          commit(ADD_GROUP_MESSAGE, res.data)
        }
      })
    }
  }

Должен сказать, что мне очень помогла библиотека vuex-class — хороший клей для vuex в сочетании с разработкой typescript. С vuex-class метод для вызова vuex в компоненте vue нужно написать только так:

// GenalChat.vue
import { namespace } from 'vuex-class'
const appModule = namespace('app')
export default class GenalChat extends Vue {
  @appModule.Getter('user') user: User;
  @appModule.Action('login') login: Function;
}

Суммировать

Chat Acounte The Chat Coat имеет полную функцию чата. В то же время я буду продолжать развивать более крутые функции в будущем. Если вам это нравится, пожалуйста, дайте мне звезду, чтобы поощрить меня!

адрес проекта

Интернет-адрес:www.genal.fun
гитхаб:genal-chat