在前端领域中,有很多需要多人协作的场景,比如设计师需要和开发工程师一起讨论和修改设计稿、团队需要协作完成前端代码等等。这时候使用一个多人协作白板就非常方便了。
本文将介绍如何使用 Node.js 和 Socket.io 实现一个多人协作白板,使得多人可以在同一画布上进行实时协作,并且能够看到彼此所做的修改。
准备工作
在开始之前,需要先准备好以下环境和工具:
- Node.js 环境(包括 npm 包管理器)
- 一个文本编辑器
- 浏览器(推荐使用 Chrome 浏览器)
创建项目
首先,打开命令行或终端窗口,进入到你的项目目录中,并执行以下命令来创建一个新的 Node.js 项目:
mkdir whiteboard cd whiteboard npm init -y
执行完毕后,你会得到一个 package.json 文件,其中包含了项目的一些基本信息和依赖项。
接下来,在项目根目录下创建一个名为 index.js
的文件,用于编写我们的主要代码。
安装依赖项
在编写代码之前,我们需要安装一些所需的依赖项。打开命令行或终端窗口,进入到项目目录中,并执行以下命令:
npm install express socket.io
这里我们安装了两个包:
- express:一个流行的 Node.js web 框架,用于搭建服务器。
- socket.io:一个实时通信库,用于实现多人协作。
编写代码
服务器端代码
打开 index.js
文件,首先我们需要引入所需的模块:
const express = require('express'); const http = require('http'); const socketIo = require('socket.io');
然后,我们需要创建一个 express 应用实例,并将其与一个 http 服务器绑定:
const app = express(); const server = http.createServer(app);
接下来,我们需要告诉 express 去哪个文件夹下面查找静态文件。我们可以通过下面的代码来实现:
app.use(express.static(__dirname + '/public'));
这样,我们就可以在 public
文件夹下面存放静态文件了。
然后,我们需要绑定一个 socket.io 服务器到我们的 http 服务器上,并监听连接事件:
const io = socketIo(server); io.on('connection', (socket) => { console.log('a user connected'); });
以上代码中,我们使用 socketIo(server)
方法将 socket.io 服务器绑定到 http 服务器上,并返回一个 io
对象,代表服务器实例。
然后,在 connection
事件中,我们通过回调函数拿到了一个 socket
对象,这个对象代表了一个连接到服务器的客户端。
现在,我们已经完成了服务器端的基本代码。接下来,我们需要编写一些和绘图相关的事件。
创建和加入房间
首先,我们需要添加一个事件让用户能够创建新的房间或加入已有的房间。我们可以通过下面的代码实现:
-- -------------------- ---- ------- --- ----- - --- ----------------------- ------ -- - ------------------ ----------- - - ------ ------------ --------- -- -- --- --------------------- ------ -- - -- -------------- - ------- - ------------------ ---------------------------------- ---
以上代码中,我们维护了一个包含所有房间信息的对象 rooms
。当用户调用 createRoom
事件时,我们通过 socket.join(room)
让该客户端加入该房间,并将这个房间信息存入 rooms
对象中。当用户调用 joinRoom
事件时,我们首先检查该房间是否存在,如果存在,就让该客户端加入该房间。
绘图相关事件
接下来,我们需要实现和绘图相关的事件,包括 startDrawing
(开始绘图)、continueDrawing
(继续绘图)、stopDrawing
(停止绘图)、undo
(撤消操作)等。下面是这些事件的具体实现代码:
-- -------------------- ---- ------- ------------------------- ------ ----- -- - -- -------------- - ------- - --------------------------- ------- ---------- ----- ------ --- ------------------------------------ ---------- ------ --- ---------------------------- ------ ----- -- - -- -------------- - ------- - ----- -------- - ------------ ----- ------- - ------------------------------------------ - --- -- --------------- --- ---------- - ------------------------ - --------------------------------------- ---------- ------ --- ------------------------ ------ ----- -- - -- -------------- - ------- - ----- -------- - ------------ ----- ------- - ------------------------------------------ - --- -- --------------- --- ---------- - ------------------------ - ----------------------------------- ---------- ------ --- ----------------- ------ -- - -- -------------- - ------- - ----- -------- - ------------ ----- -------- - ------------------ ----- ----------- - ------------------------ - --- -- ------------------- --- ---------- - ------- - -- ------------------------ - -- - ----------------------- ----------------------------- - ---- - ------------------------ ------------------------------ - ---
以上代码中,我们首先在 startDrawing
事件中将该用户开始绘图的数据存入 rooms
对象中,然后通过 socket.to(room).emit()
方法将消息广播给房间内其他成员。在 continueDrawing
和 stopDrawing
事件中,我们需要找到该用户上一次绘图信息,然后判断是否应该将当前操作的数据加入到上一次绘图信息中。在 undo
事件中,我们需要找到该用户最后一次绘图信息,然后进行撤销操作或者删除整个绘图信息。
客户端代码
现在,我们已经完成了服务器端的相关代码。接下来,我们需要在客户端实现绘图并能够和服务端通信。首先,我们需要在 public
文件夹下创建一个 HTML 文件并添加相关代码:
-- -------------------- ---- ------- --------- ----- ------ ------ ----- ---------------- ----------------- ----- ---------------- -------------------------------------------------------------------------------- ------- ----------- - ----------------- ------ ------ ----- ------- ------ - -------- ------- ------ ---- ------------------ ---- ------------ ---- ----------------- ---- ---------------------- ------ ---- ----------------- ----------- ---- ----------------- ------ ------ ------ ------- --------------------------------------- -------- ----- ------ - ----- ----- ---------- - -------------------------------------- ----- ------- - ---------------------------- --- ------- - ------ ---------------------------------------- ------- -- - ------- - ----- ----- ------- - -------------- ----- ------- - -------------- ----- - ----- --- - - ----------------------------------- ----- - - ------- - ----- ----- - - ------- - ---- --------------------------- ----- - -- - --- ------- --- --- ---------------------------------------- ------- -- - -- ---------- - ------- - ----- ------- - -------------- ----- ------- - -------------- ----- - ----- --- - - ----------------------------------- ----- - - ------- - ----- ----- - - ------- - ---- ------------------------------ ----- - -- - --- ------- --- --- -------------------------------------- -- -- - ------- - ------ -------------------------- ------ --- ------------------------- -------- ----- -- - ------------ -------- --- ---------------------------- -------- ----- -- - ------------ -------- --- ------------------------ -------- ----- -- - -- -- ------- --- ----- ---- - --- -- -- - ------------------- - -------- ----------------- - -- --------------- - -------- -- ---------- - -------------------- ----------------- --- - ---- - ----------------- --- ----------------- - -- ----- -------------- - --------------------------------- ------------------ ------ -- - ------------------------ - --- --- ---- ---- -- ----- - ----- ------ - --------------------------------- ---------------- - ---- ------------- ---------------- - --- ------- --------------------------- ---- -------------------------------- -- -- - ---- - ----- ----------------------- ------ ------------------------ - -------- ---------------------------- - ------- --- ----------------------------------- - --- ------------------ -- -- - -------------------- -- ----------------- ------------------- --- --- ---- - --- ----- ------- - ---- - ------------------- ---- - ------------------------- ------ ------------------ ------ -- - ------------------------ - --- --- ---- ---- -- ----- - ----- ------ - --------------------------------- ---------------- - ---- ------------- ---------------- - --- ------- --------------------------- ---- -------------------------------- -- -- - ---- - ----- ----------------------- ------ ------------------------ - -------- ---------------------------- - ------- --- ----------------------------------- - --- --------- ------- -------
以上代码中,我们首先引入了 socket.io 客户端库,然后创建了一个 socket 对象,表示到服务器的连接。
然后,我们获取了白板元素,并添加了鼠标事件监听器来实现绘图。当用户开始绘图时,我们通过 socket.emit('startDrawing', room, { x, y })
发送消息到服务器。当用户继续绘图时,我们通过 socket.emit('continueDrawing', room, { x, y })
发送消息给服务器。当用户停止绘图时,我们通过 socket.emit('stopDrawing', room)
发送停止事件给服务器。
在收到其他用户发送的 startDrawing
和 continueDrawing
事件时,我们通过 draw(x, y)
方法进行绘图。当收到 stopDrawing
事件时,我们不做任何操作。
在页面加载时,我们需要让用户输入一个房间名,并调用 createRoom
事件来创建该房间。然后,我们通过 rooms
事件监听器来更新房间列表。
启动服务器
最后,我们需要在命令行或终端窗口中运行以下命令,启动服务器:
node index.js
然后,在浏览器中打开 http://localhost:3000
,就可以看到多人协作白板的运行效果了。
总结
通过本文的介绍,我们了解了如何使用 Node.js 和 Socket.io 实现多人协作白板,并编写了相应的代码。通过这个例子,我们可以更好地学习实时通信相关技术,以及如何在 Node.js 环境中搭建一个 web 服务器。希望本文能对你在前端开发中使用 Node.js 和 Socket.io 实现类似实时协作功能的项目有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/646c4457968c7c53b0b47f52