如何通过Socket.io从服务器向客户端弹窗及实现白板自动同步显示
两个Socket.io+React白板应用功能实现方案
一、服务器通过Socket.io向客户端弹出窗口/对话框
核心逻辑是服务器主动发送自定义事件,客户端监听事件后触发弹窗渲染,具体实现步骤:
1. 服务器端(server.js)修改
添加自定义事件的广播逻辑,当需要触发弹窗时,将事件发送给目标客户端:
const express = require('express'); const app = express(); const path = require('path'); const http = require('http').createServer(app); const io = require('socket.io')(http); io.on('connection', onConnection); function onConnection(socket){ socket.on('drawing', (data) => { socket.broadcast.emit('drawing',data); console.log(data); }); socket.on('clear', () => { socket.broadcast.emit('clear'); console.log('data cleared........'); }); // 新增:监听客户端触发弹窗的请求,广播给所有客户端 socket.on('trigger-popup', (popupData) => { io.emit('show-popup', popupData); console.log('触发弹窗:', popupData); }); } app.get('*', (_, res) => res.sendFile(path.join(__dirname, 'build/index.html'))); const server_port = 8081; http.listen(server_port, () => { console.log(`Started on : ${server_port}`); })
2. 客户端(canvas.jsx)修改
- 添加状态控制弹窗显示:
// 在组件顶部状态定义处添加 const [showPopup, setShowPopup] = useState(false); const [popupContent, setPopupContent] = useState('');
- 在Socket连接的
useEffect中监听弹窗事件:
// 在socketRef.current.on('clear', clearCanvas); 之后添加 socketRef.current.on('show-popup', (data) => { setPopupContent(data.content); setShowPopup(true); });
- 在组件返回的JSX中添加弹窗(可自定义样式,也可用原生alert):
// 在canvas标签之前添加 {showPopup && ( <div style={{position: 'fixed', top:0, left:0, width:'100%', height:'100%', background:'rgba(0,0,0,0.5)', display:'flex', justifyContent:'center', alignItems:'center'}}> <div style={{background:'white', padding:'20px', borderRadius:'8px'}}> <p>{popupContent}</p> <button onClick={() => setShowPopup(false)} style={{marginTop:'10px'}}>关闭</button> </div> </div> )}
- 若需要从客户端触发服务器弹窗,可添加触发按钮:
// 在canvas-btn容器内添加 <div> <button onClick={() => socketRef.current.emit('trigger-popup', { content: '服务器通知:有用户打开了白板!' })} className="btn-width"> <Tooltip title="发送通知"> <NotificationIcon /> </Tooltip> </button> </div>
二、打开白板时其他用户自动显示白板
核心是用户打开白板时同步状态到服务器,服务器广播给所有客户端,客户端收到后自动渲染白板内容,同时处理新用户连接时的状态同步:
1. 服务器端(server.js)修改
添加白板状态存储,用于新用户连接时主动同步:
const express = require('express'); const app = express(); const path = require('path'); const http = require('http').createServer(app); const io = require('socket.io')(http); // 存储当前白板的最新状态(base64格式图片) let currentCanvasState = null; io.on('connection', onConnection); function onConnection(socket){ // 新用户连接时,主动发送当前白板状态 if(currentCanvasState) { socket.emit('sync-canvas', currentCanvasState); } socket.on('drawing', (data) => { socket.broadcast.emit('drawing',data); console.log(data); }); socket.on('clear', () => { socket.broadcast.emit('clear'); currentCanvasState = null; // 清空状态 console.log('data cleared........'); }); // 新增:监听客户端更新白板状态的请求,存储并广播给其他客户端 socket.on('update-canvas-state', (state) => { currentCanvasState = state; socket.broadcast.emit('sync-canvas', state); }); } app.get('*', (_, res) => res.sendFile(path.join(__dirname, 'build/index.html'))); const server_port = 8081; http.listen(server_port, () => { console.log(`Started on : ${server_port}`); })
2. 客户端(canvas.jsx)修改
- 组件挂载/白板加载完成后,发送状态到服务器:
// 修改加载localStorage的useEffect useEffect(() => { const canvas = canvasRef.current; ctx.current = canvas.getContext('2d'); //Resizing canvas.height = window.innerHeight; canvas.width = window.innerWidth; //Load from localStorage const canvasimg = localStorage.getItem('canvasimg'); if (canvasimg) { var image = new Image(); ctx.current = canvas.getContext('2d'); image.onload = function() { ctx.current.drawImage(image, 0, 0); setIsDrawing(false); // 加载完成后同步状态到服务器 socketRef.current.emit('update-canvas-state', canvasimg); }; image.src = canvasimg; } else { // 白板为空时也同步状态 socketRef.current.emit('update-canvas-state', null); } }, [ctx]);
- 在Socket连接的
useEffect中添加状态同步监听:
// 新增同步白板的函数 const syncCanvas = (canvasimg) => { const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); if(canvasimg) { const image = new Image(); image.onload = function() { ctx.drawImage(image, 0, 0); localStorage.setItem('canvasimg', canvasimg); }; image.src = canvasimg; } else { ctx.clearRect(0, 0, canvas.width, canvas.height); localStorage.removeItem('canvasimg'); } }; // 在socket监听处添加 socketRef.current.on('drawing', onDrawingEvent); socketRef.current.on('clear', clearCanvas); socketRef.current.on('sync-canvas', syncCanvas); // 新增状态同步监听
- 若有手动打开白板的按钮,在点击事件中添加状态同步:
const openWhiteboard = () => { const canvas = canvasRef.current; const canvasimg = canvas.toDataURL(); localStorage.setItem('canvasimg', canvasimg); socketRef.current.emit('update-canvas-state', canvasimg); };
内容的提问来源于stack exchange,提问作者Syed Islam
相关产品推荐
相关产品推荐

