WEB例項:開發一個聊天室應用

輕劍快馬發表於2018-09-11

前言

這篇文章介紹如何使用 Vue.js 以及 chatkit 快速的開發一個聊天室應用,chatkit 提供了一系列 api 用以更方便的開發聊天功能,原始碼地址.

建立Chatkit例項

首先需要建立一個 Chatkit 例項, 前往 chatkit控制檯 建立,建好之後新建一個房間以及使用者,將之後要用到的 instanceLocator, key 記錄到本地

WEB例項:開發一個聊天室應用

建立後端服務

新建一個 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

相關文章