本文僅對一些關鍵性的知識點進行解釋,具體請Fork源碼學習。css
Demo頁面若是沒啥人的話能夠本身新建幾個頁面複製地址進入,每一個頁面都是一個獨立的訪客,兼容PC和移動端訪問。html
Demo 演示前端
Github源碼node
博客原文git
界面佈局這個沒有啥說的,直接按本身喜愛寫就好了。也能夠直接參照本項目DEMO和源碼。github
socket.io
有先後端一致的API,因此在前端和Node端使用區別不大。docker
socket.io
最主要的API是觸發和響應自定義的事件,除了connect,message,disconnect這些事件的名字不能使用以外,你能夠觸發任何自定義的事件名稱。下面列出本項目中所使用到的一些自定義事件。npm
socket.io 官網json
# 客戶端觸發自定義事件:test socket.emit('test', data) # 服務端響應事件 socket.on('test', data => {}) 複製代碼
前端觸發事件後端
前端響應事件
鏈接服務器
import io from './assets/js/socket.io' let socket = io('ws://47.91.235.153:3000') // 鏈接服務器 socket.on('connect', function () { console.log('成功鏈接服務器') }) 複製代碼
登陸聊天室
進入頁面彈窗要求輸入用戶名,後端驗證用戶名不重複後便可關閉登陸彈窗進入聊天室。
# 發送登陸事件 function userLogin () { let loginName = document.getElementById('js-loginName').value if (loginName === '') { alert('你必須輸入用戶名') } else { // 發送登陸事件 socket.emit('login', { name: loginName }) } } oLoginBtn.addEventListener('click', userLogin) # 響應登陸狀態 socket.on('login', function (data) { if (data.status === 'ok') { loginStatus = true oLogin.style.visibility = 'hidden' } else { alert(data.text) } }) 複製代碼
系統通知
系統通知只能由服務端發送,主要返回用戶進入、離開房間的通知,並返回當前在線用戶。
socket.on('sys', function (data) { // 在線人數 oCount.innerHTML = data.count // 加入消息列表 oMessageBox.innerHTML += `<li class="sys"> <div class="name">系統通知</div> <div class="message">${data.text}</div> </li>` // 遍歷顯示在線用戶 let sUser = '' data.users.forEach(el => { sUser += `<li>${el}</li>` }); oUserBox.innerHTML = sUser }) 複製代碼
消息發送
function sendMessage () { // 獲取輸入框 let oText = document.getElementById('js-text') // 當前輸入的內容 let sText = oText.value // 爲空不提交 if (sText === '') { return false } // 觸發消息發送事件 socket.emit('message', { name: nickName, text: sText }) // 消息列表追加本人發送的消息 oMessageBox.innerHTML += `<li class="my"> <div class="name">${nickName}</div> <div class="message">${sText}</div> </li>` // 重置內容爲空 oText.value = '' // 消息列表滾動到最底部 oMessageBox.scrollTop = oMessageBox.scrollHeight } oEnter.addEventListener('click', sendMessage) 複製代碼
接收羣聊消息
接收後臺發送的廣播消息,不包含本人發送的消息。
socket.on('message', function (data) { // 消息列表追加消息 oMessageBox.innerHTML += `<li> <div class="name">${data.name}</div> <div class="message">${data.text}</div> </li>` // 消息列表滾動到底部 oMessageBox.scrollTop = oMessageBox.scrollHeight }) 複製代碼
Parcel
的使用很是簡單,不須要任何配置便可運行和打包應用程序
# 安裝 npm install -g parcel-bundler # 開發:http://localhost:1234/ 訪問 parcel index.html # 編譯 parcel build index.html 複製代碼
擁有和前端同樣的API,這裏很少作解釋
io.on('connection', function (socket) { // 響應當前鏈接用戶的事件 socket.on('test', data => {}) // 給當前鏈接的用戶發送事件 socket.emit('test', data) // 廣播給全部人 io.emit('test', data) // 廣播給除當前用戶外全部人 socket.broadcast.emit('test', data) }) 複製代碼
啓用WebSocket
var app = require('http').createServer() var io = require('socket.io')(app) // WebSocket 鏈接 io.on('connection', function (socket) { // 全部的事件觸發響應都寫在這裏 }) // 啓用3000端口 app.listen(3000, function () { console.log('WebSocket 啓用端口 on *: 3000') }) 複製代碼
用戶登陸聊天室
由於只是個練習小項目,也沒有真正的用戶中心啥的。只用了一個數組users
來存儲當前在線用戶。
socket.on('login', function (data) { // 檢查 users 中是否有重名用戶 if (users.indexOf(data.name) >= 0) { console.log(data.name + ' 已有重名用戶,請從新輸入暱稱。') // 發送登陸失敗事件 socket.emit('login', { status: 'err', text: '已有重名用戶,請從新輸入暱稱。' }) } else { // 添加一個用戶 users.push(data.name) // 設置當前用戶的 nickName socket.nickName = data.name console.log(data.name + ' 進入了房間') console.log('當前用戶', users) // 發送進入房間的系統通知 io.emit('sys', { text: socket.nickName + ' 進入了房間', count: users.length, users: users }) // 發送登陸成功的通知 socket.emit('login', { status: 'ok' }) } }) 複製代碼
消息推送
接收用戶發送的信息後廣播給除發送用戶外的全部人
socket.on('message', function (data) { socket.broadcast.emit('message', data) }) 複製代碼
用戶斷開鏈接
socket.on('disconnect', function () { let index = users.indexOf(socket.nickName) if (index >= 0) users.splice(index, 1) // 用戶離開房間發送系統通知 io.emit('sys', { text: socket.nickName + ' 離開了房間', count: users.length, users, users }) console.log(socket.nickName + '離開了房間') console.log('當前用戶', users) }) 複製代碼
項目雖小卻也是先後端分離的,因此做爲練習將項目的代碼分開部署到了不一樣的服務器。
後端代碼是部署到了阿里雲的香港服務器的,系統 CentOS 7
。使用 Docker
運行了一個node環境的容器。
阿里雲的服務器安全性很高,但也所以有超多的坑,主要注意如下幾點。
一、在服務器中安裝好 ftp
和 Docker
,安裝方法谷歌有不少 二、使用 Docker
安裝 Node
鏡像
$ Docker pull node
複製代碼
三、運行容器並掛載本地目錄(容器中的全部數據都是緩存,因此對一些須要常常變更修改的文件直接掛載到本地目錄)
$ docker run -it -p 3000:3000 \ $ --mount type=bind,source=/home/www/chat,target=/home/www/chat \ $ node:latest \ $ /bin/bash 複製代碼
四、上傳代碼並進入容器運行
將代碼文件上傳到服務器 /home/www/chat中
,而後進入容器。
$ npm install
$ node index.js
複製代碼
若是從容器退出了須要從新進入容器
# 容器ID能夠用 docker ps -a 查看 $ docker exec -it f9dd88d7f # 進入容器中的項目目錄 $ cd /home/www/chat # 安裝依賴 $ npm install # 運行項目 $ node index.js 複製代碼
前端的代碼部署相對後端來講簡單不少,由於前端代碼只有一些HTML、CSS和JS等靜態的文件,隨便找個靜態服務器放就能夠。
對於此類項目這裏強烈推薦使用阿里雲的對象存儲OSS
,超級便宜基礎版一年只須要9塊錢。
打包前端代碼
$ parcel build index.html
複製代碼
打包成功後將/dist
目錄上傳到剛剛在阿里雲中創建的OSS存儲塊中,修改index.html目錄中的資源引用爲根目錄,並將index.html移動到根目錄,而後經過綁定的域名訪問便可