WEB实例:开发一个聊天室应用

2,417 阅读2分钟

前言

这篇文章介绍如何使用 Vue.js 以及 chatkit 快速的开发一个聊天室应用,chatkit 提供了一系列 api 用以更方便的开发聊天功能,源码地址.

创建Chatkit实例

首先需要建立一个 Chatkit 实例, 前往 chatkit控制台 建立,建好之后新建一个房间以及用户,将之后要用到的 instanceLocator, key 记录到本地

建立后端服务

新建一个 Node.js 服务用来创建用户以及提供 jwt token,安装依赖 yarn add express cors pusher-chatkit-server 启动服务。

const cors = require('cors')
const express = require('express')
const Chatkit = require('pusher-chatkit-server')
const config = require('../config')

const app = express()
const PORT = config.SERVER_PORT || 4399

app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }))

// eslint-disable-next-line
const chatkit = new Chatkit.default({
  instanceLocator: config.CHATKIT_INSTANCELOCATOR,
  key: config.CHATKIT_KEY
})

app.post('/user', (req, res) => {
  const { username } = req.body

  const user = {
    id: username,
    name: username
  }

  chatkit
    .createUser(user)
    .then(() => res.status(201).json({ success: true, message: '创建用户成功', user }))
    .catch(error => {
      res.status(error.status).json({ success: false, message: error.error_description })
    })
})

app.post('/auth', (req, res) => {
  const data = chatkit.authenticate({ userId: req.query.user_id })
  res.status(data.status).json(data.body)
})

app.listen(PORT, error => {
  if (error) {
    console.log(error)
  } else {
    console.log(`Server running on port ${PORT}`)
  }
})

新建前端项目

新建一个 Vue.js 项目,建立一个用来创建新用户的表单, 表单提交到刚才创建的 express 服务的 user 路由

<form class="create__form" @submit.prevent="createUser">
  <input 
    class="create__input" 
    v-model="newUserName" 
    placeholder="输入你的名字" 
    autofocus 
    required
  />
</form>
async createUser() {
  const username = this.newUserName

  const result = await fetch(`${config.SERVER_HOST}:${config.SERVER_PORT}/user`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username })
  })
  .then(res => res.json())
  .catch(error => error)

  if (result.success) {
    const user = result.user
    this.initChatApp(user.name) // 创建用户成功
  } else {
    console.log(result)
  }
}

新建用户成功后,初始化应用

async initChatApp(userId) {
  const chatManager = new Chatkit.ChatManager({
    userId,                                           // 用户名称
    instanceLocator: config.CHATKIT_INSTANCELOCATOR,  // instanceLocator
    tokenProvider: new Chatkit.TokenProvider({       
      url: `${config.SERVER_HOST}:${config.SERVER_PORT}/auth`
    })
  })

  const currentUser = await chatManager.connect()

  const currentRoom = await currentUser
    .joinRoom({
      roomId: config.CHATKIT_ROOM_ID
    })
    .catch(error => {
      return error
    })
    
  currentUser.subscribeToRoom({
    messageLimit: 20,
    roomId: config.CHATKIT_ROOM_ID, // 在控制台建立的房间ID
    hooks: {
      onNewMessage: message => {
        this.users = this.users.map(user => {
              if (user.name === message.senderId) {
                user.online = true
              }
              return user
            })
            this.messages.push(message)
          }
        }
    })

  const messages = await currentUser
    .fetchMessages({
      roomId: config.CHATKIT_ROOM_ID,
      direction: 'older',
      limit: 20
    })
    .catch(error => {
        console.error(error)
    })

  this.currentUser = currentUser
  this.currentRoom = currentRoom
  this.users = currentRoom.userIds.filter(name => name !== currentUser.name).map(name => {
    return { name, online: false }
  })
  this.messages = messages
}

页面布局

进行布局以及UI,使用 Grid 进行快速布局, 建立用户列表,消息列表以及发送消息的表单

<ul class="chat__users">
  <li class="user-item" v-for="user of users" :key="user.id">
   <span class="name">{{ user.name }}</span>
   <span class="spot" :class="{ 'spot--online': user.online }"></span>
  </li>
</ul>
<ul class="chat__messages">
  <message-item 
    v-for="(message, index) of messages" 
    :key="index" 
    :message="message" 
    :currentUser="currentUser" 
   />
</ul>
<form class="chat__send" @submit.prevent="sendMessage">
  <input 
    class="input" 
    type="text" 
    @change="typingMessage" 
    v-model="newMessage" 
    autofocus 
    required 
    placeholder="说点什么..." 
  />
  <button class="button" type="submit">发送</button>
</form>
.chat {
  display: grid;
  grid-auto-columns: 240px auto;
  grid-auto-rows: 30px auto 70px;
  grid-template-areas:
    'users messages'
    'users messages'
    'users send';
  height: 100vh;
}  

发送消息

使用 chatkit 提供的api即可

sendMessage() {
  this.currentUser // 当前用户
    .sendMessage({
      text: this.newMessage, // 消息内容
      roomId: config.CHATKIT_ROOM_ID // 房间ID
    })
    .then(messageId => {
      this.newMessage = ''
    })
    .catch(error => {
      this.newMessage = ''
       console.log(error)
    })
}

最后

开发完成后,使用 yarn build 命令将 Vue 项目打包,然后使用 express 内置的 static 中间件挂载打包后的 dist 目录, 在浏览器中打开 express 运行的端口就可以看到效果了,文章只是简述如何开发,具体实现请看 github 源码。

app.use('/', express.static(path.join(__dirname, '/dist')))

参考

vue-chat

CHATKIT DOCS

Build a Slack Clone with React and Pusher Chatkit