ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AIRI 实战:用 VueUse `useClipboardItems` 在 Vue 应用中复制图片、富文本等任意剪贴板内容

AIRI 实战:用 VueUse `useClipboardItems` 在 Vue 应用中复制图片、富文本等任意剪贴板内容 AIRI 实战用 VueUseuseClipboardItems在 Vue 应用中复制图片、富文本等任意剪贴板内容【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi本指南围绕 VueUse 的useClipboardItems组合式函数展开讲解如何基于原生ClipboardItem在 Vue 3 项目中实现响应式、异步、支持任意内容类型图片、富文本、HTML、二进制数据的系统剪贴板读写。文中完整继承 VueUse 官方参考文档的用法与类型声明并结合 AIRI 仓库中useClipboard的真实调用场景帮助你理解剪贴板 API 的权限模型、useClipboard与useClipboardItems的差异以及如何把“复制文本”升级为“复制任意媒体内容”。背景AIRI 与 VueUse 剪贴板工具链AIRI 是一个自托管、面向桌面与 Web 的 AI 伴侣项目Web / macOS / Windows 均支持其桌面端与 Web 端界面大量基于 Vue 3 构建。仓库在多个应用与包中统一引入了vueuse/core见 apps/stage-tamagotchi/package.json 与 packages/stage-ui/package.json均通过catalog:从 pnpm workspace 的版本目录解析。仓库还内置了.agents/skills/vueuse-functions/SKILL.md技能在 Vue/Nuxt 开发中优先选用合适的 VueUse 组合式函数而不是手写重复代码其中useClipboard与useClipboardItems都被归类为Browser类别、调用规则为AUTO适用时自动使用。在这个背景下剪贴板能力是 AIRI 各端界面设置页、关于页、开发工具、错误上报的通用基础设施。useClipboardItems正是这套工具链中面向“非纯文本内容”的那一块拼图。useClipboardItems是什么useClipboardItems是对 Clipboard API。它提供对剪贴板命令剪切、复制、粘贴的响应能力对系统剪贴板的异步读取与写入基于 Permissions API 的权限门控——在没有用户授权的情况下不允许读取或修改剪贴板内容。关键点在于它是基于 ClipboardItem 的函数。任何ClipboardItem支持的内容都可以通过它复制而不仅仅限于字符串。与useClipboard的核心差异维度useClipboarduseClipboardItems数据模型纯文本stringClipboardItem[]ClipboardItems返回的“内容”reftext: ReadonlyShallowRefstringcontent: ReadonlyRefClipboardItems适用场景复制字符串、URL、Token 等复制图片、富文本、HTML、任意二进制 Blob可选能力legacy降级到document.execCommand无legacy原生 API 不支持时直接不可用useClipboard的定位是“text-only”当需求跨越纯文本、需要复制多种 MIME 类型的内容时应当选择useClipboardItems。AIRI 仓库中现有的四处useClipboard调用下面“仓库实践”一节会分析都符合“复制字符串”的定位这也反向说明了useClipboardItems的使用边界一旦复制目标变成ClipboardItem就该切换到它。快速上手复制任意内容的最小示例参考文档给出了一个可直接运行的 SFC 示例完整复刻如下来自 useClipboardItems.mdscript setup langts import { useClipboardItems } from vueuse/core const mime text/plain const source ref([ new ClipboardItem({ [mime]: new Blob([plain text], { type: mime }), }) ]) const { content, copy, copied, isSupported } useClipboardItems({ source }) /script template div v-ifisSupported button clickcopy(source) !-- by default, copied will be reset in 1.5s -- span v-if!copiedCopy/span span v-elseCopied!/span /button p Current copied: code{{ content || none }}/code /p /div p v-else Your browser does not support Clipboard API /p /template拆解这段代码的四个要点ClipboardItem的构造new ClipboardItem({ [mime]: blob })以 MIME 类型为键、Blob为值构造剪贴板条目。一个ClipboardItem可以携带多种 MIME 表示例如同时提供text/html与text/plain由系统按目标应用选择。source是一个 refuseClipboardItems({ source })接受MaybeRefOrGetterClipboardItems因此传入ref后内容变更会自动反应到copy()的默认行为中。响应式返回值content反映最近一次读取/写入的剪贴板条目copied在复制成功后置为true默认 1500ms 后自动复位isSupported用于能力检测与降级展示。权限与安全整个操作受 Permissions API 门控必须发生在用户手势如点击事件触发的上下文中否则会被浏览器拒绝。复制图片到剪贴板把text/plain换成image/png就得到了“把图片写进系统剪贴板”的能力这是useClipboard无法直接做到的async function copyImageToClipboard(file: File) { const item new ClipboardItem({ image/png: file, }) await copy([item]) }由于ClipboardItem的 value 接受BlobFile继承自Blob可以直接把用户选择的文件塞进去。复制后即可在聊天工具、文档编辑器、画图软件中直接粘贴。复制富文本HTML 纯文本双表示为同一个ClipboardItem提供多个 MIME 表示可以让粘贴方智能选择const html strongHello/strong AIRI const item new ClipboardItem({ text/html: new Blob([html], { type: text/html }), text/plain: new Blob([Hello AIRI], { type: text/plain }), }) await copy([item])这样支持 HTML 的应用粘贴出富文本只支持纯文本的应用则回退到text/plain。Options 与返回值完整类型声明解读useClipboardItems的完整类型声明摘自 useClipboardItems.mdexport interface UseClipboardItemsOptions Source, extends ConfigurableNavigator { /** * Enabled reading for clipboard * * default false */ read?: boolean /** * Copy source */ source?: Source /** * Milliseconds to reset state of copied ref * * default 1500 */ copiedDuring?: number } export interface UseClipboardItemsReturnOptional extends Supportable { content: ReadonlyRefClipboardItems copied: ReadonlyShallowRefboolean copy: Optional extends true ? (content?: ClipboardItems) Promisevoid : (text: ClipboardItems) Promisevoid read: () void } /** * Reactive Clipboard API. * * see https://vueuse.org/useClipboardItems * param options * * __NO_SIDE_EFFECTS__ */ export declare function useClipboardItems( options?: UseClipboardItemsOptionsundefined, ): UseClipboardItemsReturnfalse export declare function useClipboardItems( options: UseClipboardItemsOptionsMaybeRefOrGetterClipboardItems, ): UseClipboardItemsReturntrue选项参数表选项类型默认值说明readbooleanfalse是否启用对剪贴板内容的读取会监听 copy/cut 等事件并刷新contentsourceMaybeRefOrGetterClipboardItems—调用copy()且不传参时使用的默认剪贴板内容copiedDuringnumber1500copied置为true后多少毫秒复位为false此外UseClipboardItemsOptions继承自ConfigurableNavigator意味着可以像其他 VueUse Browser 函数一样通过window注入自定义的 navigator 环境如测试中的 mock。返回值解析属性类型说明contentReadonlyRefClipboardItems最近一次读取/写入的剪贴板条目ClipboardItem[]启用read后随事件刷新copiedReadonlyShallowRefboolean复制成功后为truecopiedDuring毫秒后自动复位copy(content?: ClipboardItems) Promisevoid异步写入剪贴板传入source时参数可选read() void手动触发一次剪贴板读取刷新content重载的实战含义两个重载签名值得注意不传source时返回UseClipboardItemsReturnfalse此时copy必须显式传入ClipboardItems传入sourceMaybeRefOrGetterClipboardItems时返回UseClipboardItemsReturntrue此时copy参数可选缺省使用source。这与useClipboard的重载设计一脉相承对比 useClipboard.md 中的UseClipboardOptions/UseClipboardReturnTypeScript 会据此在编译期约束你的调用方式避免漏传参数。读取剪贴板read与content默认read: false时useClipboardItems只负责写入不主动触碰剪贴板内容这既符合最小权限原则也避免无谓的权限弹窗。需要“读取并响应剪贴板变化”时开启readconst { content, read } useClipboardItems({ read: true }) // 手动触发一次读取 read()content会持有读取到的ClipboardItem[]。要注意在多数浏览器中读取剪贴板同样要求文档处于聚焦状态、且页面获得clipboard-read权限而写入通常只需要clipboard-write。实际产品中建议把“读取”做成显式用户操作如点击“粘贴预览”按钮后再read()而不是在挂载时自动读取。用useClipboard对照理解权限模型useClipboard的参考文档useClipboard.md同样强调访问剪贴板内容受 Permissions API 门控无用户授权时不允许读取或改写。两个函数共享同一套浏览器安全模型差异只在数据形态useClipboard返回text: ReadonlyShallowRefstringuseClipboardItems返回content: ReadonlyRefClipboardItems。此外useClipboard独有legacy选项可在原生 Clipboard API 缺失时降级到document.execCommand(copy)default falseuseClipboardItems依赖ClipboardItem本身无法降级因此isSupported的能力检测在这里更加关键。AIRI 仓库中的剪贴板实践从useClipboard到升级路径仓库虽然没有直接调用useClipboardItems但多处useClipboard的真实用法恰好勾勒出“何时需要升级到useClipboardItems”的决策边界场景一复制格式化错误报告useClipboardapps/stage-tamagotchi/src/renderer/pages/about.vue 在“关于/更新”页收集 Bug 报告const { copy: copyToClipboard, isSupported: isClipboardSupported } useClipboard() async function onBugReportSubmit(payload: BugReportDialogSubmitPayload) { bugReportSending.value true try { if (!isClipboardSupported.value) throw new Error(Clipboard API is unavailable) await copyToClipboard(payload.formattedReport) showBugReportDialog.value false } catch (error) { bugReportSubmitError.value error } finally { bugReportSending.value false } }这是useClipboard的标准形态复制对象是“格式化后的文本报告”属于纯字符串场景。若未来希望错误报告同时携带 Markdown/HTML 表示就能顺势改用useClipboardItems构造多 MIME 的ClipboardItem。场景二复制认证 TokenuseClipboardlegacyapps/stage-tamagotchi/src/renderer/pages/settings/connection/index.vue 在服务器连接设置页复制 WebSocket 认证 Tokenimport { refDebounced, useClipboard } from vueuse/core const authTokenInput shallowRef(authToken.value) const authTokenInputDebounced refDebounced(authTokenInput, 500) const { copied: authTokenCopied, copy: copyAuthToken, isSupported: isClipboardSupported } useClipboard({ source: authTokenInput, legacy: true }) const canCopyAuthToken computed(() isClipboardSupported.value authTokenInput.value.length 0)三个值得学习的细节source传 refauthTokenInput是shallowRefToken 变化后copy()无参调用也能复制最新值legacy: true桌面端若运行在较旧的 WebView 环境中、原生 Clipboard API 缺失会降级到execCommand保持复制可用isSupported驱动按钮禁用canCopyAuthToken同时检查能力与内容长度避免空复制。Token 同样是字符串因此用useClipboard而非useClipboardItems。场景三复制图片 Data URLuseClipboardpackages/stage-pages/src/pages/devtools/image.vue 是开发工具页读取用户选择的图片后复制其 Data URLconst image refFile() const imageDataURL refstring() const { copy } useClipboard({ source: imageDataURL }) async function handleFileChange(event: Event) { const target event.target as HTMLInputElement const file target.files?.[0] if (file) { image.value file const dataURL await readAsDataURL(file) imageDataURL.value dataURL } }注意这里复制的是Data URL 字符串因此useClipboard够用。但如果需求变成“把图片本身复制到剪贴板粘贴后得到图片文件”就必须升级为useClipboardItems——这正是前面“复制图片到剪贴板”一节展示的new ClipboardItem({ image/png: file })写法。同一个上传图片的交互useClipboard复制“文本形式的 URL”useClipboardItems复制“二进制形式的图片”两者并不互斥而是按粘贴目标选择。场景四渲染错误页兜底复制useClipboardpackages/stage-ui/src/components/scenes/stage-render-error.vue 同样使用useClipboard({ legacy: true })提供错误信息复制能力与场景一/二同属文本复制。小结AIRI 现有四处调用全部命中useClipboard的“纯文本”定位当仓库未来需要“复制图片/富文本/混合媒体”时useClipboardItems是唯一合适的选择。两者的选择标准可以概括为一句决策规则复制目标是字符串 →useClipboard可加legacy降级复制目标是ClipboardItem图片、HTML、Blob、混合 MIME→useClipboardItems。实践建议与注意事项先做能力检测始终用isSupported包裹功能入口参考文档的示例模板v-ifisSupported就是推荐姿势不支持时给出“Your browser does not support Clipboard API”之类的降级文案。写入必须处于用户手势上下文copy()返回的 Promise 在权限不足或脱离用户激活时会 reject务必try/catch并向用户反馈参考 AIRI 关于页的onBugReportSubmit错误处理模式。读取权限更严格默认不开read确需读取时用显式用户操作触发并处理clipboard-read权限被拒的情况。copiedDuring可调默认 1500ms 复位copied若复制成功后需要展示更长的成功反馈可自行调大。多 MIME 条目一个ClipboardItem可携带多个表示text/htmltext/plainimage/png等让不同粘贴目标拿到最适合的格式。与useClipboard共用决策矩阵参考 .agents/skills/vueuse-functions/SKILL.md 的指导原则——能用 VueUse 组合式函数实现的需求优先复用现成函数保持代码简洁、可维护、高性能。参考资料本文主文档.agents/skills/vueuse-functions/references/useClipboardItems.md姊妹函数文档.agents/skills/vueuse-functions/references/useClipboard.md技能总览.agents/skills/vueuse-functions/SKILL.md仓库使用案例apps/stage-tamagotchi/src/renderer/pages/about.vueBug 报告复制apps/stage-tamagotchi/src/renderer/pages/settings/connection/index.vueToken 复制 legacy 降级packages/stage-pages/src/pages/devtools/image.vue图片 Data URL 复制packages/stage-ui/src/components/scenes/stage-render-error.vue渲染错误兜底复制【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表