本文仅对一些关键性的知识点进行解释,具体请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移动到根目录,而后经过绑定的域名访问便可