nw.js桌面软件开发系列 第0.1节 HTML5和桌面软件开发的碰撞
nw.js桌面软件开发系列 第0.1节 HTML5和桌面软件开发的碰撞大家好我是你们的技术博主小明。今天我们要聊一个有趣的话题——HTML5和桌面软件开发这两者看似风马牛不相及但在nw.js的撮合下它们竟然碰撞出了耀眼的火花。## 从浏览器到桌面一场技术革命还记得那个年代吗我们开发桌面软件要用C、C#或者Java写一个简单的记事本程序都要面对复杂的窗口句柄和消息循环。而Web开发者呢他们只需要写HTML、CSS和JavaScript就能在浏览器里做出炫酷的交互效果。但是浏览器有它的局限性无法访问文件系统、不能调用系统API、不能在任务栏里独立运行。直到nw.js的出现这一切都变了。nw.js原名node-webkit是一个基于Chromium和Node.js的桌面应用开发框架。它让Web开发者可以用熟悉的HTML5技术来开发桌面软件同时还能调用Node.js的底层能力。## HTML5的桌面潜力你以为它只是网页很多人对HTML5的认识还停留在“网页技术”的层面。但你知道吗HTML5已经具备了桌面软件开发的很多基础能力-离线存储localStorage和IndexedDB可以让应用在离线状态下工作-Canvas和WebGL可以绘制复杂的图形和3D场景-Web Workers实现多线程处理-拖放API支持文件拖入操作-音频/视频处理多媒体能力但这些还远远不够我们需要一个“桥梁”来连接Web世界和桌面世界。nw.js就是这座桥梁。## 第一个nw.js应用Hello World让我们从最基础的开始创建一个简单的nw.js应用。首先你需要安装nw.js可以从官网下载SDK版本。创建一个项目文件夹里面包含以下两个文件### package.json - 应用配置文件json{ name: hello-nwjs, main: index.html, window: { title: 我的第一个nw.js应用, width: 800, height: 600, resizable: true, icon: icon.png }, node-remote: *, webkit: { plugin: true }}### index.html - 主页面文件html!DOCTYPE htmlhtmlhead meta charsetUTF-8 titleHello nw.js/title style body { font-family: Microsoft YaHei, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; text-align: center; padding: 50px; } h1 { font-size: 3em; text-shadow: 2px 2px 4px rgba(0,0,0,0.5); } button { padding: 15px 30px; font-size: 1.2em; border: none; border-radius: 25px; background: white; color: #667eea; cursor: pointer; margin: 20px; transition: transform 0.3s; } button:hover { transform: scale(1.1); } #info { margin-top: 30px; padding: 20px; background: rgba(255,255,255,0.1); border-radius: 10px; } /style/headbody h1 Hello nw.js!/h1 p这是用HTML5技术开发的桌面应用/p !-- 演示Node.js能力 -- button onclickcheckSystem()检测系统信息/button button onclickreadFile()读取文件/button div idinfo p点击按钮查看效果/p /div script // 使用Node.js的API const os require(os); // 引入Node.js的os模块 const fs require(fs); // 引入Node.js的fs模块 function checkSystem() { // 获取系统信息 const info document.getElementById(info); const systemInfo strong系统信息/strongbr 操作系统${os.type()} ${os.release()}br 主机名${os.hostname()}br 总内存${(os.totalmem() / 1024 / 1024 / 1024).toFixed(2)} GBbr 空闲内存${(os.freemem() / 1024 / 1024 / 1024).toFixed(2)} GBbr CPU架构${os.arch()}br 运行时间${os.uptime()} 秒 ; info.innerHTML systemInfo; } function readFile() { // 读取当前目录下的一个文件 const info document.getElementById(info); try { const content fs.readFileSync(package.json, utf-8); info.innerHTML strongpackage.json内容/strongbrpre${content}/pre; } catch (error) { info.innerHTML 读取文件失败${error.message}; } } /script/body/html运行方法将nw.js的可执行文件与项目文件夹放在同一目录然后执行nw .命令。你会看到一个漂亮的窗口点击按钮可以读取系统信息和文件内容。## 碰撞的火花Web技术 系统能力上面的例子展示了nw.js最核心的能力在HTML页面中直接调用Node.js的API。这意味着我们可以1.访问文件系统读写文件、创建目录、删除文件2.使用操作系统功能获取系统信息、执行命令、操作进程3.网络通信创建HTTP服务器、WebSocket连接4.调用系统对话框文件选择器、通知提示5.使用原生模块通过npm安装各种Node.js模块## 更复杂的例子一个简单的文件管理器让我们用nw.js做一个更实用的应用——一个简单的文件管理器### file-manager.htmlhtml!DOCTYPE htmlhtmlhead meta charsetUTF-8 title简单文件管理器/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Microsoft YaHei, sans-serif; background: #f5f5f5; padding: 20px; } .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); padding: 20px; } .toolbar { display: flex; gap: 10px; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #eee; } .toolbar input { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; } .toolbar button { padding: 10px 20px; background: #667eea; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; } .toolbar button:hover { background: #5a6fd6; } .file-list { list-style: none; } .file-item { display: flex; align-items: center; padding: 12px 15px; border-bottom: 1px solid #f0f0f0; cursor: pointer; transition: background 0.2s; } .file-item:hover { background: #f8f9ff; } .file-icon { margin-right: 15px; font-size: 20px; } .file-name { flex: 1; } .file-size { color: #999; font-size: 12px; } .back-btn { padding: 10px 20px; background: #ff6b6b; color: white; border: none; border-radius: 5px; cursor: pointer; margin-bottom: 10px; } .back-btn:hover { background: #ee5a5a; } /style/headbody div classcontainer h2 stylemargin-bottom: 20px; 简单文件管理器/h2 div classtoolbar input typetext idpathInput placeholder输入路径例如 C:\\Users value. button onclicknavigate()导航/button button onclickcreateFile()创建文件/button /div button classback-btn onclickgoBack()← 上一级/button ul classfile-list idfileList li classfile-item点击导航按钮查看文件/li /ul /div script const fs require(fs); const path require(path); // 当前路径 let currentPath process.cwd(); function navigate() { const input document.getElementById(pathInput); const targetPath input.value.trim(); // 如果输入的是相对路径转换为绝对路径 if (!path.isAbsolute(targetPath)) { currentPath path.resolve(currentPath, targetPath); } else { currentPath targetPath; } // 更新输入框显示当前路径 input.value currentPath; // 读取目录内容 loadDirectory(currentPath); } function loadDirectory(dirPath) { const fileList document.getElementById(fileList); fileList.innerHTML ; // 清空列表 try { // 读取目录内容 const files fs.readdirSync(dirPath); // 对文件和目录进行排序目录在前 const sortedFiles files.sort((a, b) { const statA fs.statSync(path.join(dirPath, a)); const statB fs.statSync(path.join(dirPath, b)); if (statA.isDirectory() !statB.isDirectory()) return -1; if (!statA.isDirectory() statB.isDirectory()) return 1; return a.localeCompare(b); }); sortedFiles.forEach(file { const fullPath path.join(dirPath, file); const stat fs.statSync(fullPath); const li document.createElement(li); li.className file-item; // 根据类型显示不同的图标 const icon stat.isDirectory() ? : ; // 格式化文件大小 let size ; if (!stat.isDirectory()) { const bytes stat.size; if (bytes 1024) { size bytes B; } else if (bytes 1024 * 1024) { size (bytes / 1024).toFixed(1) KB; } else { size (bytes / 1024 / 1024).toFixed(1) MB; } } li.innerHTML span classfile-icon${icon}/span span classfile-name${file}/span span classfile-size${size}/span ; // 点击目录时进入 if (stat.isDirectory()) { li.addEventListener(click, () { currentPath fullPath; document.getElementById(pathInput).value currentPath; loadDirectory(currentPath); }); } fileList.appendChild(li); }); } catch (error) { fileList.innerHTML li classfile-item❌ 读取目录失败${error.message}/li; } } function goBack() { const parentPath path.dirname(currentPath); if (parentPath ! currentPath) { currentPath parentPath; document.getElementById(pathInput).value currentPath; loadDirectory(currentPath); } } function createFile() { const fileName prompt(请输入文件名); if (fileName) { try { const filePath path.join(currentPath, fileName); fs.writeFileSync(filePath, , utf-8); loadDirectory(currentPath); // 刷新文件列表 } catch (error) { alert(创建文件失败 error.message); } } } // 初始化加载当前目录 loadDirectory(currentPath); /script/body/html这个文件管理器虽然简单但已经展现了nw.js的强大能力完整的文件系统操作、路径处理、文件读写而且所有界面都是用HTML5技术构建的。## 为什么选择nw.js在桌面软件开发领域nw.js不是唯一的选项。还有Electron、Tauri等框架。但nw.js有它独特的优势1.简单直接不需要复杂的构建工具一个HTML文件就能开始2.Node.js深度集成可以直接在页面中调用Node.js API3.原生窗口控制可以设置窗口大小、菜单、托盘等4.跨平台Windows、macOS、Linux都能运行5.社区活跃有很多插件和扩展## 总结HTML5和桌面软件开发的碰撞就像是两个技术世界的联姻。nw.js作为这场联姻的牵线者让Web开发者能够用自己熟悉的技能开发出功能强大的桌面应用。从简单的Hello World到文件管理器我们看到了这种技术融合的魔力。虽然nw.js在性能上可能不如原生应用但对于大部分桌面应用来说它的表现已经足够出色。而且随着硬件性能的提升和Web技术的进步这种差距正在不断缩小。如果你是一个Web开发者想尝试桌面软件开发nw.js绝对是一个值得投入的方向。它不仅能让你快速上手还能让你的应用拥有Web应用的所有优点跨平台、易于部署、更新方便。下一节我们将深入探讨nw.js的窗口管理和原生API调用敬请期待

相关新闻

DellFanManagement深度解析:戴尔笔记本风扇控制的终极实战手册

DellFanManagement深度解析:戴尔笔记本风扇控制的终极实战手册

DellFanManagement深度解析:戴尔笔记本风扇控制的终极实战手册 【免费下载链接】DellFanManagement A suite of tools for managing the fans in many Dell laptops. 项目地址: https://gitcode.com/gh_mirrors/de/DellFanManagement 如果你曾经在深夜加班时…

2026/10/18 0:21:57 阅读更多 →
3分钟搞定无损歌词下载:音乐爱好者必备的网易云QQ音乐歌词提取神器

3分钟搞定无损歌词下载:音乐爱好者必备的网易云QQ音乐歌词提取神器

3分钟搞定无损歌词下载:音乐爱好者必备的网易云QQ音乐歌词提取神器 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为音乐播放器缺少歌词而烦恼&#xff…

2026/10/18 4:18:30 阅读更多 →
3分钟免费解锁Mac读写Windows硬盘:Nigate跨平台文件同步终极指南

3分钟免费解锁Mac读写Windows硬盘:Nigate跨平台文件同步终极指南

3分钟免费解锁Mac读写Windows硬盘:Nigate跨平台文件同步终极指南 【免费下载链接】Free-NTFS-for-Mac Nigate: An open-source NTFS utility for Mac. It supports all Mac models (Intel and Apple Silicon), providing full read-write access, mounting, and man…

2026/10/18 4:19:38 阅读更多 →

最新新闻

context-mode:为命令行工具设计可复现的上下文状态管理层

context-mode:为命令行工具设计可复现的上下文状态管理层

你有没有遇到过这种场景:打开终端,先export一串环境变量,再cd到项目目录,然后才开始真正干活。如果只是顺手敲两下还好,但如果你同时在维护三五个项目,每个项目还对应不同的 API 地址、不同的分支策略、不同…

2026/10/20 3:52:15 阅读更多 →
Linux数据盘格式化实战:设备确认、分区、mkfs与挂载避坑指南

Linux数据盘格式化实战:设备确认、分区、mkfs与挂载避坑指南

1. 格式化前先搞清楚这几件事接到一台机器,客户说数据盘满了,想要重新格式化,我第一句话永远都是:数据备份了吗?这不是客套,是血泪教训。Linux下格式化硬盘这个操作,新手看起来就是一条mkfs.ext…

2026/10/20 3:52:15 阅读更多 →
多传感器数据分析:从nuScenes坐标系对齐到BEV特征构建全流程

多传感器数据分析:从nuScenes坐标系对齐到BEV特征构建全流程

简介:面向自动驾驶研究与工程实践,这份资源以nuScenes多模态数据集为核心,提供基于Python的解析与可视化代码,适合需要处理LiDAR、摄像头、毫米波雷达等传感器数据的研究者与开发者。压缩包共8个文件,以Python脚本为主…

2026/10/20 3:52:15 阅读更多 →
Kubernetes四大节点组件原理与故障排查指南

Kubernetes四大节点组件原理与故障排查指南

1. 什么是Kubernetes节点组件?它到底在解决什么问题?你可能已经听过“K8s是云原生时代的操作系统”这种说法,但真正用过的人会发现:这句话不是比喻,而是事实——只不过这个“操作系统”不装在你的笔记本里,…

2026/10/20 3:52:15 阅读更多 →
构建个人技能体系:从清单到矩阵的迭代实战

构建个人技能体系:从清单到矩阵的迭代实战

“skills”这个标题看上去太简单了,简单到一眼扫过去容易直接略过。但你真把它当成一个项目来对待的时候,它可能是很多人一直想做、却迟迟没动手做对的那件事:把自己的技能体系盘清楚、搭起来、用起来。我不是在讲一个概念,我是把…

2026/10/20 3:52:15 阅读更多 →
本地推理实战:用llama.cpp与ollama部署LFM2.5-1.2B小模型

本地推理实战:用llama.cpp与ollama部署LFM2.5-1.2B小模型

1. 上手前的心里话:为什么大家都盯着小模型本地推理最近圈子里聊本地大模型,基本绕不开两个东西:llama.cpp 和 ollama。而我这段时间一直在折腾的主角,是 LFM2.5-1.2B 这个模型。别看它只有 1.2B 参数,实测下来每秒能跑…

2026/10/20 3:51:14 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →