网页包装为桌面应用(electron版)

该框架通过整合Chromium内核和Node.js运行时环境,允许开发者使用JavaScript、HTMLCSS构建兼容Windows、macOSLinux系统的桌面应用,架构采用主进程处理系统级交互、渲染进程依托Chromium展示界面及IPC通信机制。(说白了就是包装)

一、项目概述

使用 Electron 将在线网页封装成独立的 Windows 桌面应用程序 Dr.aiVoss

二、搭建electron

第一步(文件初始化)

新建一个空的文件夹,编辑器中打开这个文件夹(例如:my-electron-app)

cd 你新创建的文件

复制代码
npm init

初始化时可以一站式回车,当然也可以填入相应的内容信息。执行完之后会生成package.json文件。

第二步(安装electron)

复制代码
npm install --save-dev electron

安装之后

html 复制代码
npm install
html 复制代码
npm install --save-dev electron-builder

主要是运行整个项目以及打包整个项目生成exe文件。

安装的过程中可能会比较慢,影响因素是文件过大以及网络问题。

第三步(package.json 关键配置)

html 复制代码
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "electron .",
    "build:win": "electron-builder --win"
  },
  "build": {
    "appId": "com.hithinker.voss",
    "productName": "Dr.aiVoss",
    "files": ["index.js", "package.json"],
    "win": {
      "target": [{"target": "nsis", "arch": ["x64"]}],
      "icon": "public/icon/icons.ico"
    }
  },
  "devDependencies": {
    "electron": "^39.2.7",
    "electron-builder": "^26.0.12"
  }
}

第四步(编写文件)

根目录创建 index.html

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'">
    <title>Hello World! - My Electron App</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>,
    Chromium <span id="chrome-version"></span>,
    and Electron <span id="electron-version"></span>.
  </body>
</html>

根目录创建 index.js(我在原有基础配置上加上了屏幕的缩放以及控制台显示)

html 复制代码
// 在文件头部引入 Node.js 中的 path 模块
const path = require('path')
// app 它控制应用程序的事件生命周期。
// BrowserWindow 模块,它创建和管理应用程序 窗口。
const { app, BrowserWindow, globalShortcut } = require('electron');

// 保存主窗口引用
let mainWindow = null

// 创建浏览器窗口
function createWindow () {
    //__dirname 字符串指向当前正在执行脚本的路径 (在本例中,它指向你的项目的根文件夹)
    mainWindow = new BrowserWindow({
        width: 1000,
        height: 800,
        resizable: true,
        minWidth: 800,
        minHeight: 600,
        backgroundColor: '#fff',
        icon: path.join(__dirname, 'public/icon/icons.ico'),
        webPreferences: {
            nodeIntegration: true
        }
      })

      // 本地文件
      //mainWindow.loadFile('index.html')
      // 线上页面
       mainWindow.loadURL('https://www.csdn.net/')

      // 打开控制台
      // mainWindow.webContents.openDevTools()

      // 启用页面缩放功能
      mainWindow.webContents.on('did-finish-load', () => {
          // 设置缩放级别限制
          mainWindow.webContents.setVisualZoomLevelLimits(1, 5)
          // 启用视觉缩放
          mainWindow.webContents.setZoomFactor(1.0)
      })

      // 监听鼠标滚轮缩放
      mainWindow.webContents.on('zoom-changed', (event, zoomDirection) => {
          const currentZoom = mainWindow.webContents.getZoomFactor()
          if (zoomDirection === 'in') {
              // 放大
              mainWindow.webContents.setZoomFactor(Math.min(currentZoom + 0.1, 5.0))
          } else {
              // 缩小
              mainWindow.webContents.setZoomFactor(Math.max(currentZoom - 0.1, 0.25))
          }
      })

      // 注册缩放快捷键
      registerZoomShortcuts()

      // 监听窗口内的键盘事件(用于 F12 等按键)
      mainWindow.webContents.on('before-input-event', (event, input) => {
          // F12 打开/关闭开发者工具
          if (input.key === 'F12') {
              mainWindow.webContents.toggleDevTools()
          }
      })

};

// 保存当前缩放级别
let zoomLevel = 1.0

// 注册缩放快捷键
function registerZoomShortcuts() {
    // Ctrl + = 放大
    globalShortcut.register('CommandOrControl+=', () => {
        if (mainWindow) {
            zoomLevel = Math.min(zoomLevel + 0.1, 5.0)
            mainWindow.webContents.setZoomFactor(zoomLevel)
        }
    })

    // Ctrl + Shift + = 放大(针对不需要按 Shift 就能按 + 的键盘)
    globalShortcut.register('CommandOrControl+Shift+=', () => {
        if (mainWindow) {
            zoomLevel = Math.min(zoomLevel + 0.1, 5.0)
            mainWindow.webContents.setZoomFactor(zoomLevel)
        }
    })

    // Ctrl + - 缩小
    globalShortcut.register('CommandOrControl+-', () => {
        if (mainWindow) {
            zoomLevel = Math.max(zoomLevel - 0.1, 0.25)
            mainWindow.webContents.setZoomFactor(zoomLevel)
        }
    })

    // Ctrl+Shift+I 打开/关闭开发者工具
    globalShortcut.register('CommandOrControl+Shift+I', () => {
        if (mainWindow) {
            mainWindow.webContents.toggleDevTools()
        }
    })

    // F5 或 Ctrl+R 刷新页面
    globalShortcut.register('F5', () => {
        if (mainWindow) {
            mainWindow.reload()
        }
    })

    globalShortcut.register('CommandOrControl+R', () => {
        if (mainWindow) {
            mainWindow.reload()
        }
    })

    // Ctrl+Shift+R 强制刷新(清除缓存)
    globalShortcut.register('CommandOrControl+Shift+R', () => {
        if (mainWindow) {
            mainWindow.webContents.reloadIgnoringCache()
        }
    })
}

// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
app.on('window-all-closed', function () {
	if (process.platform !== 'darwin') app.quit()
})

// 应用退出时注销所有快捷键
app.on('will-quit', () => {
    globalShortcut.unregisterAll()
})

// 部分 API 在 ready 事件触发后才能使用。
// 在 Electron 中,只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口
app.whenReady().then(() => {
    createWindow()
    app.on('activate', function () {
      // 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他打开的窗口,那么程序会重新创建一个窗口。
      if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

三、项目启动与打包

终端执行之后会直接打开网页

html 复制代码
npm start
html 复制代码
npm run build
或者
npm run build:win

直接拖拽到桌面或直接创建快捷方式(直接点击打开即可)

四、实现的功能

1. 窗口管理

  • ✅ 自定义窗口大小(1000x800)
  • ✅ 可调整窗口大小
  • ✅ 最小尺寸限制(800x600)
  • ✅ 自定义应用图标

2. 缩放功能

  • Ctrl + 鼠标滚轮 - 页面缩放
  • Ctrl + = - 放大(每次 +10%)
  • Ctrl + - - 缩小(每次 -10%)
  • Ctrl + 0 - 重置到 100%
  • ✅ 缩放范围:25% ~ 500%

3. 开发者工具

  • F12 - 打开/关闭控制台
  • Ctrl + Shift + I - 打开/关闭控制台

4. 页面刷新

  • F5 - 刷新页面
  • Ctrl + R - 刷新页面
  • Ctrl + Shift + R - 强制刷新(清除缓存)

五、注意事项

1. 图标要求

  • .ico 文件必须包含至少 256x256 像素
  • 推荐包含多尺寸:16x16, 32x32, 48x48, 256x256

https://www.ico51.cn/ 在线转换

实现自定义图标

问题分析:

  1. npm start 显示了自定义图标 ✅
  2. 打包时因为网络问题无法下载签名工具,导致图标无法嵌入到 exe 文件中 ❌

解决方案有几个:

方案1:手动下载签名工具缓存

复制代码
# 手动下载 winCodeSign-2.6.0.7z 并放到缓存目录

方案2:使用 ResHacker 或其他工具手动修改图标

方案3:暂时接受现状 (虽然打包失败,但 exe 文件已经生成在 dist/win-unpacked/Dr.aiVoss.exe,只是图标是默认的)

方案4:在能连接 GitHub 的环境下重新打包

由于网络问题,当前情况下:

  • 开发模式 (npm start) - 图标正常 ✅
  • 打包后 (dist/win-unpacked/Dr.aiVoss.exe) - 使用默认图标 ❌

建议:

  1. 先使用 dist/win-unpacked/Dr.aiVoss.exe 这个可执行文件
  2. 或者使用代理/VPN 后重新运行 npm run build:win
  3. 或者使用工具如 Resource Hacker 手动替换 exe 图标

2. 开发 vs 打包

  • 开发模式 :通过代码中的 icon 属性显示图标
  • 打包模式 :通过 package.jsonbuild.win.icon 配置

3. 网络问题

  • 打包时需要下载签名工具(winCodeSign)
  • 如遇网络问题,可使用 dist/win-unpacked/ 中的 exe 文件

六、总结

通过 Electron 成功实现了:

  1. 将在线网页封装为独立桌面应用
  2. 完整的窗口管理功能
  3. 用户体验优化(缩放、刷新等)
  4. 自定义应用图标和名称
  5. 生成可分发的 .exe 文件

这种方式非常适合将现有的 Web 应用快速打包成桌面应用,无需重写代码。

相关推荐
用户91743965392 小时前
基于SqlSugar开发框架的基础上快速开发H5端的移动应用
前端·负载均衡
Yesterday不想说话2 小时前
Promise的总结
前端
C_心欲无痕2 小时前
nodejs - npm和package.json文件解析
前端·npm·json
H@Z*rTE|i2 小时前
webpack 打包流程(极简记忆口诀)
前端·webpack·node.js
@菜菜_达3 小时前
前端 HTML 入门(标签)
前端·html
智航GIS3 小时前
7.1 自定义函数
前端·javascript·python
BlackWolfSky3 小时前
React中文网课程笔记1—快速入门
前端·笔记·react.js
A_one20103 小时前
利用npm内置命令构建脚本工具
前端·npm·node.js
哔哩哔哩技术3 小时前
2025年哔哩哔哩技术精选技术干货
前端·后端·架构