Electron聊天室|react19+electron41仿微信客户端|electron桌面聊天【完结版】

0 阅读5分钟

2026/8经过两周左右爆肝研发,最新版Electron41结合React19最新全家桶技术搭建轻量级桌面端聊天系统,正式完结啦!

未标题-3.png

p6.gif

实现技术

  • 编码工具:vscode
  • 跨端技术框架:electron41.1.0
  • 前端框架:react^19.2.8+react-router-dom^7.18.2
  • ui组件库:@arco-design/web-react^2.66.16
  • 状态管理:zustand^5.0.14
  • 打包管理:electron-builder^26.15.3
  • 前端构建工具:vite^8.2.0
  • 样式处理:sass^1.102.0
  • electron整合react插件:vite-plugin-electron^1.1.1

p3.gif

p2.gif

electron-react19-winchat聊天项目实现了封装electron/react多窗口管理,包含聊天、通讯录、收藏、朋友圈、视频、我的等页面模块。

未标题-2.png

项目技术框架

基于最新前端工具vite8+react19结合electron41初始搭建项目模板,react19 hook语法编码页面。

360截图20260814230626520.png

001360截图20260815002223109.png

p1.gif

前端入口配置

import '@arco-design/web-react/es/_util/react-19-adapter'
import { createRoot } from 'react-dom/client'
import './style.scss'
import App from './App.jsx'
import '@arco-design/web-react/dist/css/arco.css'

import { launchApp } from '@/windows/actions'

launchApp().then(config => {
  if(config) {
    window.config = config
  }

  createRoot(document.getElementById('root')).render(
    <App />
  )
})

360截图20260814230626526.png

360截图20260814231711398.png

360截图20260814232312430.png

360截图20260814232903568.png

360截图20260814233912243.png

360截图20260814235338481.png

360截图20260815001116383.png

360截图20260815001823416.png

项目布局模板

项目整体布局结构如下图:

360截图20260814230626523.png

7d054604f5201c86f8c61a807f74cd28_1289798-20260816001918690-1209424541.png

<div className='ra__container flex-c'>
  <div className='ra__layout flexbox flex-col'>
    <div className='ra__layout-body flex1 flexbox'>
      {/* 菜单栏 */}
      <Menubar />

      {/* 侧边栏 */}
      <Sidebar />
      
      {/* 主内容区 */}
      <div className='ra__layout-main flex1 flexbox flex-col'>
        <Toolbar />
        { Lazyload(<Outlet />) }
      </div>
    </div>
  </div>
</div>

002360截图20260815002434144.png

002360截图20260815002520302.png

002360截图20260815002613273.png

003360截图20260815003139958.png

003360截图20260815003235706.png

003360截图20260815003336410.png

004360截图20260815003458278.png

004360截图20260815003645188.png

005360截图20260815003919701.png

005360截图20260815004006135.png

005360截图20260815004216566.png

005360截图20260815004254113.png

007360截图20260815004537970.png

007360截图20260815004735861.png

electron主线程/预加载文件配置

a50d5d34fb54184549ee95ce84161eca_1289798-20260816003855352-1002903401.png

/**
 * electron主进程配置
 * @author andy
 */

import { app, BrowserWindow } from 'electron'

import { WindowManager } from '../src/windows/index.js'

// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true

const createWindow = () => {
  let win = new WindowManager()
  win.create({isMajor: true})
  // 系统托盘管理
  win.trayManager()
  // 监听ipcMain事件
  win.ipcManager()
}

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if(BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if(process.platform !== 'darwin') app.quit()
})
/**
 * electron预加载文件
 * @author andy
 */

const { contextBridge, ipcRenderer } = require('electron')
// MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
ipcRenderer.setMaxListeners(0)

contextBridge.exposeInMainWorld(
  'electron',
  {
    // 通过 channel 向主进程发送异步消息。主进程使用 ipcMain.on() 监听 channel
    send: (channel, args) => {
      ipcRenderer.send(channel, args)
    },

    // 通过 channel 向主进程发送消息,并异步等待结果。主进程应该使用 ipcMain.handle() 监听 channel
    invoke: (channel, args) => {
      return new Promise(resolve => ipcRenderer.invoke(channel, args).then(data => resolve(data)).catch(e => console.log(e)))
    },

    // 监听 channel 事件
    on: (channel, func) => {
      console.log('receive event')
      ipcRenderer.on(channel, (event, ...args) => func(event, ...args))
    },

    // 一次性监听事件
    once: (channel, func) => {
      ipcRenderer.once(channel, (event, ...args) => func(event, ...args))
    },

    // 浏览器打开链接
    openExternal: (url) => ipcRenderer.send('open-external', url)
  }
)

008360截图20260815094128714.png

008360截图20260815094608269.png

008360截图20260815094850662.png

008360截图20260815094913551.png

008360截图20260815095007100.png

008360截图20260815095406352.png

008360截图20260815095910693.png

008360截图20260815100349569.png

008360截图20260815100501589.png

008360截图20260815100649220.png

008360截图20260815100939035.png

009360截图20260815101030806.png

009360截图20260815101654767.png

010360截图20260815101739654.png

electron+react实现无边框窗口拖拽/标题栏

image.png

electron封装自定义右上角最小化/最大化/关闭按钮。

ea92342c3c06f45d3bc435790b9430ef_1289798-20260816004600631-152115188.png

function Winbtns(props) {
  const {
    color,
    // 窗口是否可以最小化
    minimizable = true,
    // 窗口是否可以最大化
    maximizable = true,
    // 窗口是否可关闭
    closable = true,
    // 设置层叠
    zIndex = 2026,
    style,
    ...rest
  } = props

  const appState = appStore()

  const [hasMaximized, setHasMaximized] = useState(false)
  const [isResizable, setIsResizable] = useState(true)
  const [isMaximizable, setIsMaximizable] = useState(true)

  useEffect(() => {
    // 用户是否可以手动调整窗口大小
    window.electron.invoke('win-isResizable').then(res => {
      setIsResizable(res)
    })

    // 窗口是否可以最大化
    window.electron.invoke('win-isMaximizable').then(res => {
      setIsMaximizable(res)
    })

    // 初始窗口是否最大化
    window.electron.invoke('win-isMaximized').then(res => {
      setHasMaximized(res)
    })

    // 实时监听窗口是否最大化
    window.electron.on('win-maximized', (e, data) => {
      setHasMaximized(data)
    })
  }, [])

  // 最小化
  const handleWinMin = () => {
    window.electron.invoke('win-min')
  }
  // 最大化/还原
  const handleWinMax2Min = () => {
    window.electron.invoke('win-toggle').then(res => {
      setHasMaximized(res)
    })
  }
  // 关闭
  const handleWinClose = () => {
    if(window.config.isMajor) {
      const modal = Modal.confirm({
        icon: null,
        content: <div style={{fontSize: 15}}>是否最小化到托盘,不退出程序?</div>,
        focusLock: false,
        style: {width: 275, borderRadius: 12, padding: '10px 25px 20px'},
        footer: <div style={{textAlign: 'right'}}>
          <Button type='text' shape='round' size='small' onClick={() => {
            modal.close()
            setTimeout(() => {
              winSet('hide', window.config.id)
            }, 150)
          }}>最小化至托盘</Button>
          <Button type='text' status='danger' shape='round' size='small' onClick={() => {
            appState.logout()
            winSet('close')
          }}>退出</Button>
        </div>
      })
    } else {
      winSet('close', window.config.id)
    }
  }

  return (
    <>
      <div {...rest} className="ra__winbtns flexbox flex-alignc" style={{ zIndex: zIndex, ...style }}>
        <div className="ra__winbtns-actions flexbox flex-alignc" style={{ color: color }}>
          {isTrue(minimizable) && <a className="min" title="最小化" onClick={handleWinMin}><i className="elec-icon elec-icon-min"></i></a>}
          {(isTrue(maximizable) && isResizable && isMaximizable) &&
            <a className="max" title={hasMaximized ? '向下还原' : '最大化'} onClick={handleWinMax2Min}>
              {hasMaximized ? <i className="wicon elec-icon elec-icon-restore"></i> : <i className="elec-icon elec-icon-max"></i>}
            </a>
          }
          {isTrue(closable) && <a className="close" title="关闭" onClick={handleWinClose}><i className="elec-icon elec-icon-quit"></i></a>}
        </div>
      </div>
    </>
  )
}

electron+react新开多窗口封装

360截图20260814231223045.png

/**
 * 创建新窗口
 * @param {object} args 窗口配置参数 {url: '/about', width: 500, height: 300, ...}
 */
export function winCreate(args) {
  window.electron.send('win-create', args)
}

未标题-1.png

// 登录窗口
export function loginWindow() {
  winCreate({
    url: '/login',
    title: '登录',
    width: 320,
    height: 380,
    isMajor: true,
    resizable: false,
    maximizable: false,
    alwaysOnTop: true
  })
}

// 关于窗口
export function aboutWindow() {
  winCreate({
    url: '/win/about',
    title: '关于',
    width: 375,
    height: 300,
    minWidth: 375,
    minHeight: 300,
    maximizable: false,
    alwaysOnTop: true,
  })
}

// 设置窗口
export function settingWindow() {
  winCreate({
    url: '/win/setting',
    title: '设置',
    width: 550,
    height: 470,
    resizable: false,
    maximizable: false,
  })
}

electron实现自定义系统托盘/消息菜单

p7.gif

/** 
 * 系统托盘图标
 */
trayManager() {
  if(this.tray) return
  const trayMenu = Menu.buildFromTemplate([
    {
      label: '打开主界面',
      icon: join(__root, 'resources/tray-win.png'),
      click: () => {
        this.winMain.restore()
        this.winMain.show()
      }
    },
    {
      label: '设置',
      icon: join(__root, 'resources/tray-setting.png'),
      click: () => this.sendByMainWin('win-ipcdata', {type: 'WINIPC_SETTINGWIN', value: null})
    },
    {
      label: '锁定系统',
      click: () => null,
    },
    {
      label: '关闭托盘闪烁',
      click: () => this.trayFlash(false)
    },
    {
      label: '关于',
      click: () => this.sendByMainWin('win-ipcdata', {type: 'WINIPC_ABOUTWIN', value: null})
    },
    {
      label: '退出聊天室',
      icon: join(__root, 'resources/tray-exit.png'),
      click: () => {
        dialog.showMessageBox(this.winMain, {
          title: '提示',
          message: '确定要退出聊天程序吗?',
          buttons: ['取消', '最小化托盘', '确认退出'],
          type: 'error',
          noLink: false,
          cancelId: 0,
        }).then(res => {
          // console.log(res)
          const index = res.response
          if(index == 0) {
            console.log('用户取消操作')
          }else if(index == 1) {
            console.log('最小化到托盘')
            this.winMain.hide()
          }else if(index == 2) {
            console.log('退出程序')
            this.sendByMainWin('win-ipcdata', {type: 'WINIPC_LOGOUT', value: null})
            app.quit()
          }
        })
      }
    }
  ])
  this.tray = new Tray(this.trayIcon)
  this.tray.setContextMenu(trayMenu)
  this.tray.setToolTip(app.name)
  this.tray.on('double-click', () => {
    console.log('tray double clicked!')
    this.winMain.restore()
    this.winMain.show()
  })
  this.tray.on('mouse-enter', (event, position) => {
    // console.log('鼠标划入', position)
    if(!this.hasFlash) return
    this.sendByMainWin('win-ipcdata', {type: 'WINIPC_MESSAGEWIN', value: position})
    // 简略消息通知
    /* this.tray.displayBalloon({
      iconType: 'none',
      title: 'Electron38研发组',
      content: 'Electron38+Vite7仿微信客户端聊天。'
    }) */
  })
  this.tray.on('mouse-leave', (event, position) => {
    // console.log('鼠标离开')
  })
}

Ok,基于Electron41构建React19+Arco+Vite8桌面聊天应用就分享到这里,整个项目涉及到的知识点还是很多的,希望以上分享对大家有些帮助!

React19+DeepSeek V4+ArcoDesign网页版流式AI智能系统模板

React19-Admin后台管理系统|vite8+react19+arco+zustand通用后台模板

Electron38-Wechat电脑端聊天|vite7+electron38仿微信桌面端聊天系统

Tauri2.8+Vue3聊天系统|vite7+tauri2+element-plus客户端仿微信聊天程序

最新版Flutter3.41+Dart3.11仿写抖音APP直播+短视频+聊天应用程序

最新研发flutter3.41+bitsdojo_window+getx客户端仿微信聊天Exe应用

vite8-webos网页版os管理|Vue3+Vite8.0+ArcoDesign搭建pc端os桌面系统

uniapp+deepseek流式ai助理|uniapp+vue3对接deepseek三端Ai问答模板

Vite8+DeepSeek网页版AI助手|vue3+arco本地web版ai流式打字问答系统

Flutter3.41+DeepSeek智能AI应用|flutter3+getx+dio流式ai对话app模板

Electron41+Vite8.0+DeepSeek桌面端AI助手|electron+vue3流式ai系统

最新版Flutter3.41+Dart3.11仿写抖音APP直播+短视频+聊天应用程序

Flutter3-MacOS桌面OS系统|flutter3.41+window_manager客户端OS模板

Tauri2-Vite7Admin客户端管理后台|tauri2.9+vue3+element-plus后台系统