本文仅对一些关键性的知识点进行解释,具体请Fork源码学习。
Demo页面如果没啥人的话可以自己新建几个页面复制地址进入,每个页面都是一个独立的访客,兼容PC和移动端访问。
界面布局这个没有啥说的,直接按自己喜好写就行了。也可以直接参照本项目DEMO和源码。
socket.io
有前后端一致的API,所以在前端和Node端使用区别不大。
socket.io
最主要的API是触发和响应自定义的事件,除了connect,message,disconnect这些事件的名字不能使用之外,你可以触发任何自定义的事件名称。下面列出本项目中所使用到的一些自定义事件。
# 客户端触发自定义事件: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环境的容器。
阿里云的服务器安全性很高,但也因此有超多的坑,主要注意以下几点。
1、在服务器中安装好 ftp
和 Docker
,安装方法谷歌有很多 2、使用 Docker
安装 Node
镜像
$ Docker pull node
复制代码
3、运行容器并挂载本地目录(容器中的所有数据都是缓存,所以对一些需要经常变动修改的文件直接挂载到本地目录)
$ docker run -it -p 3000:3000 \
$ --mount type=bind,source=/home/www/chat,target=/home/www/chat \
$ node:latest \
$ /bin/bash
复制代码
4、上传代码并进入容器运行
将代码文件上传到服务器 /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移动到根目录,然后通过绑定的域名访问即可