You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:45:34