news 2026/9/5 18:36:09

Electron clipboard 模块实战指南:基于 W3C Clipboard API 的系统剪贴板操作与自定义 MIME 格式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Electron clipboard 模块实战指南:基于 W3C Clipboard API 的系统剪贴板操作与自定义 MIME 格式

Electron clipboard 模块实战指南:基于 W3C Clipboard API 的系统剪贴板操作与自定义 MIME 格式

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

Electron 的clipboard模块运行在主进程,是当前版本中面向系统剪贴板进行复制/粘贴的唯一官方入口。本篇以 clipboard API 文档 为核心,完整覆盖其 W3C 风格方法(read/write/readText/writeText/has/clear)、Electron 自定义 MIME 格式(bookmark、findtext、osclipboard、web前缀)以及 Linux 特有的selection剪贴板,并结合仓库中的 JavaScript 封装层(lib/browser/api/clipboard.ts)与 C++ 原生实现(shell/browser/api/electron_api_clipboard.cc)说明底层调用链,读完后你可以掌握跨平台多格式剪贴板读写、原子写入与原生格式穿透(raw format round-trip)的完整实现方案。

模块定位与设计模型

clipboard模块的设计目标是复刻 W3C Clipboard API(navigator.clipboard)的接口形态,但提供的是不受隐私沙箱限制的原生剪贴板访问能力:

  • clipboard.read()返回Promise<ClipboardItem[]>,其中ClipboardItem携带一个或多个 MIME 类型到Blob负载的映射;
  • clipboard.write()接受ClipboardItem[]数组,所有条目在一次调用内原子性地提交到系统剪贴板;
  • 与渲染进程的navigator.clipboard不同,主进程的clipboard能读到文件的真实绝对路径(例如text/uri-list不做隐私脱敏),并且能访问平台级原始剪贴板格式。

需要注意一条已废弃行为(见 docs/api/clipboard.md 中的 history 注释):在渲染进程中直接使用clipboardAPI 已被废弃,该模块只在主进程中可用,进程模型定义参见 glossary。

[!NOTE]ClipboardItem不能被用户代码继承(Electron 内置类的通用限制),详见 FAQ。

Electron 自定义 MIME 格式

除了标准 MIME 类型(text/plaintext/htmltext/rtfimage/pngimage/jpeg等),Electron 暴露了一小组自定义格式,遵循 W3C 自定义格式提案,但使用electron前缀而非web以避免命名冲突:

自定义格式平台说明
electron application/bookmark全平台(读取侧 Linux 不支持)URL 书签。唯一例外:读写两侧都是ClipboardBookmark对象({ title, url })而非Blob,即getType('electron application/bookmark')解析为对象
electron application/findtext仅 macOS活跃应用"查找"粘贴板(find pasteboard)的内容
electron application/osclipboard;format="<name>"全平台平台特定剪贴板格式的原始负载。<name>是平台格式名(Windows 如HTML Format,macOS 如public.utf8-plain-text)。clipboard.read()还会把没有标准 MIME 映射的任意平台格式归入该自定义格式暴露,因此原始 OS 格式可以"原样往返"(写进去和读出来是同一个 MIME 字符串)

此外,read()write()都接受任意 MIME 类型,包括以web前缀(后跟空格,如web application/x.my-format)开头的 W3C web 自定义格式:

const { clipboard, ClipboardItem } = require('electron') async function writeClipboard () { await clipboard.write([ new ClipboardItem({ 'web application/x.my-app-clip': new Blob(['arbitrary payload']) }) ]) } writeClipboard()

核心方法详解

clipboard.readText()

返回Promise<string>,以纯文本形式读取剪贴板内容,对标 W3Cnavigator.clipboard.readText

const { clipboard } = require('electron') async function readText () { await clipboard.writeText('hello i am a bit of text!') const text = await clipboard.readText() console.log(text) // 'hello i am a bit of text!' } readText()

从源码结构看,electron_api_clipboard.cc 中Clipboard::ReadText是常见调用的"快速路径",直接走ui::Clipboard::ReadText,绕过了getType()的逐 MIME 分派开销;在 Windows 上若 Unicode 读取为空,还会自动回退到ReadAsciiTextReadText中的IS_WIN分支)。

clipboard.writeText(text)

  • textstring

返回Promise<void>,文本写入完成时 resolve,对标 W3Cnavigator.clipboard.writeText

const { clipboard } = require('electron') async function writeClipboardText () { await clipboard.writeText('hello i am a bit of text!') } writeClipboardText()

clipboard.read()

返回Promise<ClipboardItem[]>,resolve 为携带剪贴板全部内容的ClipboardItem数组:

const { clipboard } = require('electron') async function dumpClipboard () { const items = await clipboard.read() for (const item of items) { for (const type of item.types) { const blob = await item.getType(type) console.log(type, blob) } } } dumpClipboard()

原生侧的类型枚举管线EnumerateAvailableTypes(见 electron_api_clipboard.cc)解释了types数组是如何聚合出来的,它按顺序合并三个来源:

  1. ReadAvailableStandardAndCustomFormatNames— 标准 MIME 类型及web前缀的 W3C 自定义格式;
  2. GetAllAvailableFormats— 其余所有原始平台格式。标准格式会被过滤掉(避免text/plainelectron application/osclipboard;format="public.utf8-plain-text"重复暴露同一条内容),其余包装为 osclipboard MIME;macOS 上还在此处探测 find pasteboard 并追加findtext伪 MIME;
  3. ReadURL(非 Linux)— 若剪贴板中有书签,则追加electron application/bookmark

因此read()返回的types是一份完整的"聚合 MIME 列表",而每个类型的具体负载由getType(type)按需从平台剪贴板惰性读取。

clipboard.write(data)

  • dataClipboardItem[] — 通过new ClipboardItem({ [mime]: payload })构造的条目数组

返回Promise<void>。单次write()调用中的所有条目原子地提交到系统剪贴板:

const { clipboard, ClipboardItem, nativeImage } = require('electron') const png = nativeImage.createFromPath('/path/to/icon.png').toPNG() async function writeClipboard () { await clipboard.write([ new ClipboardItem({ 'text/plain': 'hello', 'text/html': '<b>hello</b>', 'image/png': new Blob([png], { type: 'image/png' }), 'electron application/bookmark': { title: 'Electron', url: 'https://electronjs.org' } }) ]) } writeClipboard()

JS 封装层如何保证"先解析、后原子提交"可以清晰地从源码看出:lib/browser/api/clipboard.ts 中的wrapClipboard拦截write,先把每个ClipboardItemBlob/Promise负载全部 resolve 成BufferkToNative),再经一次同步的原生write提交。而 C++ 侧Clipboard::Write(electron_api_clipboard.cc)用单个ui::ScopedClipboardWriter依次写入所有条目,析构时才真正提交——这就是原子性的实现来源。

两个值得注意的运行时约束(均可在测试与源码中验证):

  • write()参数必须是ClipboardItem数组,非数组或非ClipboardItem元素会抛出TypeError
  • clipboard.read()返回的ClipboardItem是"只读"的轻量读取器,不能回传给write(),必须重新构造新的ClipboardItem(见 lib/browser/api/clipboard-item.ts 中[kToNative]的显式拒绝逻辑)。

clipboard.has(mimetype)

  • mimetypestring - 要检查的 MIME 类型

返回Promise<boolean>,剪贴板中存在该 MIME 数据时 resolve 为true。要检查原始平台格式(如public/utf8-plain-text),需使用 osclipboard 自定义格式:

const { clipboard } = require('electron') async function check () { const hasFormat = await clipboard.has('text/html') console.log(hasFormat) // 'true' 或 'false' const rawFormat = 'electron application/osclipboard;format="public/utf8-plain-text"' const hasRawFormat = await clipboard.has(rawFormat) } check()

实现上,hasread共用同一条聚合枚举管线(EnumerateAvailableTypes后做成员判定),所以hasread暴露的每一种 MIME——标准类型、web前缀格式、osclipboard 原始格式、bookmark、macOS findtext——都保持一致的判定结果。

clipboard.clear()

清除剪贴板内容(同步方法)。

安全边界:MIME 键即能力面

clipboard-item.md 文档中有一条重要警告:不要直接用不可信对象构造ClipboardItem(例如从渲染进程经 IPC 传来的负载)。MIME 键本身是能力面:text/uri-list会把真实文件引用放到 OS 剪贴板(允许粘贴文件到其他应用),electron application/osclipboard;format=...web前缀格式会写入原始平台数据。从未经自己审核的数据构建ClipboardItem之前,务必对 MIME 类型和负载结构做白名单校验。

Linux 特有:clipboard.selection属性

在 Linux 上还存在一个selection剪贴板(对应 X11 的 PRIMARY 选择),通过clipboard.selection子命名空间暴露,它与顶层clipboard接口完全同构:

const { clipboard } = require('electron') async function run () { await clipboard.selection.writeText('Example string') console.log(await clipboard.selection.readText()) } run()

两个剪贴板相互独立:通过clipboard.selection写入的数据不会影响clipboard.read()的返回值(反之亦然)。注意selection剪贴板不支持W3C web 自定义格式。

[!NOTE]clipboard.selection是只读属性:Linux 上为一个Clipboard对象,暴露与顶层一致的readwritereadTextwriteTexthasclear方法;其他平台为undefined

从源码结构看,electron_api_clipboard.cc 中的Initialize在 Linux 分支上调用两次PopulateClipboardObject——分别绑定kCopyPastekSelection两个ui::ClipboardBuffer——同一套 C++ 方法通过绑定期注入不同的 buffer 实例化为两个 JS 对象。JS 层(lib/browser/api/clipboard.ts)仅在binding.selection存在时才挂selection包装对象。

测试视角的行为验证

仓库中的 spec/api-clipboard-spec.ts 对上述文档声明提供了逐项的行为验证,可作为可信行为参考:

  • image/*负载通过clipboard.write+getType完成NativeImage往返(写入后读回的数据 URL 一致);
  • 剪贴板只有文本时,read()types中不出现任何 image 类型;
  • readText()/writeText()均返回Promise,且 Unicode 文本(如千江有水千江月,万里无云万里天)正确往返;
  • has()对已写入的标准 MIME、web前缀自定义 MIME(如web text/plain+electron-test)、以及 osclipboard 原始格式(public/utf8-plain-text)均能正确返回true,未写入时返回false

小结

能力API关键约束
纯文本读写readText()/writeText(text)返回 Promise;Windows 自动回退 ASCII 读取
多格式原子写入write(ClipboardItem[])所有条目单次原子提交;不能接受read()产生的读取器
全量读取read()返回单元素ClipboardItem[]types为聚合 MIME 列表,负载惰性读取
存在性检查has(mimetype)read()的暴露面严格一致;原始格式需用 osclipboard MIME
清空clear()同步
Linux 选择剪贴板clipboard.selection.*与系统剪贴板隔离;不支持 web 自定义格式

这套 API 的实用价值在于:主进程既能以 W3C 标准形态操作常见文本/HTML/图片/书签/文件列表,又能通过electron application/osclipboard;format="..."穿透到 Windows 注册格式、macOS pasteboard 类型等任意平台格式,实现与其他桌面应用的数据互操作——这正是"以 W3C Clipboard API 为骨架、以平台原始格式为逃生舱"的完整落地。

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 18:34:37

构建大分辨率水下海鲜检测数据集:YOLOv5格式实践与调优指南

简介&#xff1a;本资源是面向计算机视觉初学者与目标检测实践者的高质量水下生物目标检测数据集&#xff0c;专为YOLOv5模型训练与验证设计&#xff0c;解决水下低对比度、高散射场景中海鲜动植物识别难的问题&#xff0c;适用于科研实验、课程设计及竞赛基线模型构建。压缩包…

作者头像 李华
网站建设 2026/9/5 18:32:16

Apktool 如何把 APK 拆成可编辑文件

Apktool 如何把 APK 拆成可编辑文件 【免费下载链接】Apktool A tool for reverse engineering Android apk files 项目地址: https://gitcode.com/GitHub_Trending/ap/Apktool Apktool 是一个安卓 APK 逆向工具&#xff0c;一行命令把安装包拆成资源文件和 Smali 代码&…

作者头像 李华
网站建设 2026/9/5 18:32:13

RT-Thread下STM32L4集成Paho-MQTT:从网络适配到低功耗物联网通信实战

简介&#xff1a;本资源是一套基于RT-Thread操作系统的STM32L496嵌入式MQTT通信完整工程&#xff0c;面向物联网开发工程师与嵌入式进阶学习者&#xff0c;解决超低功耗MCU在资源受限场景下接入云平台的核心问题。工程已集成lwIP网络栈、Paho-MQTT C客户端库及适配STM32L4系列的…

作者头像 李华
网站建设 2026/9/5 18:31:20

事业单位E类职测策略选择:底层逻辑与稳定拿分方法详解

先问大家一个很现实的问题&#xff1a;事业单位联考E类职测里&#xff0c;哪个模块最容易拿分&#xff1f;很多同学第一反应是策略选择。 理由也很简单&#xff0c;它不像数学运算需要大量计算&#xff0c;也不像图形推理需要“灵光一现”&#xff0c;更不像资料分析那样有复杂…

作者头像 李华
网站建设 2026/9/5 18:30:02

rembg 背景移除从报错到跑通:3 条命令搞定安装与使用

rembg 背景移除从报错到跑通&#xff1a;3 条命令搞定安装与使用 【免费下载链接】rembg Rembg is a tool to remove images background 项目地址: https://gitcode.com/GitHub_Trending/re/rembg 你是不是也卡在 The CLI dependencies are not installed 这句提示上&am…

作者头像 李华