npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nowclipboard

v1.1.9

Published

现代剪贴板工具库 - 零依赖,支持浏览器和 Node.js 双环境

Readme

NowClipboard

中文 | English

现代剪贴板工具库 -- 零依赖,支持浏览器和 Node.js 双环境。

特性

  • 现代 API 优先 -- 优先使用 navigator.clipboard.writeText(),自动降级到 document.execCommand
  • Promise 异步 -- 所有操作返回 Promise,支持 async/await
  • 自动重试 -- 内置可配置的指数退避重试机制,支持超时控制和 AbortSignal 取消
  • 双环境支持 -- 浏览器 + Node.js(Windows PowerShell / macOS pbcopy / Linux xclip/xsel
  • 读写双向 -- 支持写入(复制/剪切)和读取(粘贴)剪贴板
  • 富内容读取 -- readRich() 读取剪贴板中的文本、HTML 和图片
  • 粘贴监听 -- 通过 onPaste 监听粘贴事件,自动解析文本、HTML、文件
  • 变更监听 -- 通过 onChange 轮询监听剪贴板内容变化
  • 权限检测 -- 通过 queryPermission 查询剪贴板读写权限状态
  • HTML 属性绑定 -- 通过 data-nc-* 属性声明式绑定复制行为
  • 事件委托 -- 支持选择器字符串、Element、NodeList 三种触发方式
  • 资源安全 -- 完善的 destroy() 方法防止内存泄漏,destroy 后调用方法会抛错
  • 图片复制 -- 支持 Blob、File、HTMLImageElement、HTMLCanvasElement、URL 等多种图片源
  • 富文本复制 -- 同时复制 HTML + 纯文本,自动降级到 execCommand
  • Node.js 写入 -- write() / writeImage() 在 Node.js 中写入文本和图片到系统剪贴板
  • 多格式写入 -- writeFormats() 一次写入多种 MIME 类型
  • 剪贴板历史 -- History 类自动记录剪贴板变更,支持搜索和持久化
  • 跨标签页同步 -- onSync() 基于 BroadcastChannel 自动同步复制操作
  • iOS Safari 适配 -- 针对移动端 Safari 的特殊降级处理
  • data URL 优化 -- data: URL 直接解码为 Blob,不走 fetch 网络请求
  • TypeScript -- 内置完整的 .d.ts 类型定义
  • ESM 支持 -- 提供 ESM 模块版本,支持 import 语法和 Tree-shaking
  • 零依赖 -- 单文件,无任何外部依赖

文件说明

| 文件 | 说明 | |------|------| | NowClipboard.js | 完整版(带注释,便于阅读和调试) | | NowClipboard.min.js | 压缩版(生产环境推荐) | | NowClipboard.esm.mjs | ESM 模块版本(支持 import 语法) | | NowClipboard.d.ts | TypeScript 类型定义文件 | | demo.html | 交互式演示页面 |

安装

npm install nowclipboard --save

快速开始

浏览器引入

<!-- 开发环境 -->
<script src="NowClipboard.js"></script>

<!-- 生产环境(推荐) -->
<script src="NowClipboard.min.js"></script>

Node.js 引入

var NowClipboard = require('nowclipboard');

AMD 引入

require(['NowClipboard'], function (NowClipboard) {
  // ...
});

ESM 引入

// 默认导入
import NowClipboard from 'nowclipboard';

// 命名导入(按需引入)
import { copy, read, readRich, copyImage, copyRich, onChange, write, writeImage, writeFormats, onSync, History } from 'nowclipboard';

使用方式

1. HTML 属性绑定(声明式)

通过 data-nc-* 属性指定复制行为,无需写额外 JS 逻辑:

<!-- 复制指定文本 -->
<button class="btn" data-nc-text="要复制的内容">复制文本</button>

<!-- 复制目标元素的内容 -->
<input id="source" value="输入框内容">
<button class="btn" data-nc-target="#source">复制输入框</button>

<!-- 剪切目标元素的内容 -->
<textarea id="content">可编辑内容</textarea>
<button class="btn" data-nc-target="#content" data-nc-action="cut">剪切</button>
<script src="NowClipboard.js"></script>
<script>
  var clipboard = new NowClipboard('.btn');

  clipboard.on('success', function (e) {
    console.log('复制成功:', e.text);
    e.clearSelection();
  });

  clipboard.on('error', function (e) {
    console.error('复制失败:', e.error);
  });
</script>

2. 配置项初始化(编程式)

通过函数动态控制复制行为:

var clipboard = new NowClipboard('.btn', {
  // 自定义操作类型
  action: function (trigger) {
    return trigger.getAttribute('data-action') || 'copy';
  },

  // 自定义目标元素
  target: function (trigger) {
    var id = trigger.getAttribute('data-target');
    return document.getElementById(id);
  },

  // 自定义复制文本
  text: function (trigger) {
    return '当前时间: ' + new Date().toLocaleString();
  },

  // 容器元素(用于降级方案中的临时元素挂载)
  container: document.body,

  // 重试配置
  retries: 3,        // 最大重试次数(默认 2)
  retryDelay: 200,   // 基础延迟 ms(默认 100,指数退避)
  timeout: 5000,     // 超时 ms(默认 0,不超时)

  // AbortSignal 取消操作
  signal: abortController.signal
});

3. 静态方法(直接调用)

不需要实例化,直接复制文本:

// 复制文本
NowClipboard.copy('Hello World')
  .then(function (text) {
    console.log('已复制:', text);
  })
  .catch(function (err) {
    console.error('失败:', err.message);
  });

// 使用 AbortSignal 取消操作
var controller = new AbortController();
NowClipboard.copy('Hello World', { signal: controller.signal });

// 1 秒后取消
setTimeout(function () { controller.abort(); }, 1000);

// async/await 写法
async function doCopy() {
  try {
    var text = await NowClipboard.copy('Hello World');
    console.log('已复制:', text);
  } catch (err) {
    console.error('失败:', err.message);
  }
}

4. 静态剪切

var textarea = document.querySelector('#myTextarea');

NowClipboard.cut(textarea).then(function (text) {
  console.log('已剪切:', text);
});

// 带重试配置
NowClipboard.cut(textarea, { retries: 3, timeout: 5000 }).then(function (text) {
  console.log('已剪切:', text);
});

5. 读取剪贴板

// 浏览器(需要 HTTPS + 用户授权)
NowClipboard.read().then(function (text) {
  console.log('剪贴板内容:', text);
});

// 带配置
NowClipboard.read({ retries: 3, timeout: 3000 }).then(function (text) {
  console.log('读取成功:', text);
});

6. 读取剪贴板富内容

读取剪贴板中的纯文本、HTML 和图片。需要 HTTPS + 支持 clipboard.read() API 的现代浏览器。

NowClipboard.readRich().then(function (result) {
  console.log('纯文本:', result.text);
  console.log('HTML:', result.html);
  console.log('图片数量:', result.images.length);
});

// 带重试和超时配置
NowClipboard.readRich({ retries: 3, timeout: 5000 });

7. 粘贴事件监听

// 监听整个页面的粘贴事件
var listener = NowClipboard.onPaste(null, function (data) {
  console.log('文本:', data.text);
  console.log('HTML:', data.html);
  console.log('文件:', data.files);
  // data.originalEvent 为原始 paste 事件
});

// 监听指定选择器(事件委托)
var listener2 = NowClipboard.onPaste('.paste-area', function (data) {
  console.log('粘贴到目标区域:', data.text);
});

// 销毁监听
listener.destroy();

8. 剪贴板变更监听

轮询检测剪贴板内容变化,当内容改变时触发回调。

var watcher = NowClipboard.onChange(function (data) {
  console.log('剪贴板内容变更:', data.text);
}, 1000); // 轮询间隔 1000ms(默认)

// 销毁监听
watcher.destroy();

⚠️ onChange 使用轮询方式读取剪贴板,浏览器中需要页面获焦且有读取权限。频繁轮询可能在某些浏览器触发权限弹窗。

9. 权限检测

// 检测读取权限
NowClipboard.queryPermission('read').then(function (result) {
  console.log('读取权限:', result.state); // 'granted', 'denied', 或 'prompt'
});

// 检测写入权限
NowClipboard.queryPermission('write').then(function (result) {
  console.log('写入权限:', result.state);
});

10. 复制图片

需要 HTTPS + 现代浏览器(支持 ClipboardItem API)。

// 复制图片 URL
NowClipboard.copyImage('https://example.com/photo.png')
  .then(function (blob) {
    console.log('图片已复制,大小:', blob.size);
  });

// 复制 data: URL(不走网络请求,直接解码为 Blob)
NowClipboard.copyImage('data:image/png;base64,...');

// 复制 Canvas 画布
var canvas = document.querySelector('#myCanvas');
NowClipboard.copyImage(canvas);

// 复制 img 元素
var img = document.querySelector('#myImage');
NowClipboard.copyImage(img);

// 复制任意 Blob
var blob = new Blob([data], { type: 'image/png' });
NowClipboard.copyBlob(blob);

11. 复制富文本

同时复制 HTML 和纯文本,粘贴时保留格式。

NowClipboard.copyRich({
  text: '纯文本内容',
  html: '<b>加粗</b>的 <em>富文本</em> 内容'
}).then(function (result) {
  console.log('已复制:', result.text, result.html);
});

// 支持 AbortSignal
var controller = new AbortController();
NowClipboard.copyRich({
  text: '纯文本',
  html: '<b>富文本</b>',
  signal: controller.signal
});

通过 HTML 属性绑定富文本复制:

<div id="rich-content">
  <h3>标题</h3>
  <p>这是 <strong>加粗</strong> 的内容</p>
</div>
<button class="btn" data-nc-target="#rich-content" data-nc-html="true">
  复制富文本
</button>

12. Node.js 环境

var NowClipboard = require('./NowClipboard.js');

NowClipboard.copy('从服务端复制的内容').then(function (text) {
  console.log('已写入系统剪贴板:', text);
}).catch(function (err) {
  console.error('失败:', err.message);
});

// 读取系统剪贴板
NowClipboard.read().then(function (text) {
  console.log('剪贴板内容:', text);
});

Node.js 系统命令依赖:

| 操作系统 | 写入命令 | 读取命令 | 备注 | |---------|---------|---------|------| | Windows | powershell -EncodedCommand | powershell -EncodedCommand | 使用 Base64 编码传递文本,避免 Unicode 编码问题 | | macOS | pbcopy | pbpaste | 系统内置 | | Linux | xclip | xclip -o | 需安装:sudo apt install xclip | | Linux (降级) | xsel | xsel -o | 备选:sudo apt install xsel |

13. 写入文本(write)

write()copy() 的别名,在浏览器和 Node.js 中均可使用。语义上更强调"写入"操作。

// 浏览器和 Node.js 通用
NowClipboard.write('写入剪贴板的文本').then(function (text) {
  console.log('已写入:', text);
});

14. 写入图片(writeImage)

在浏览器和 Node.js 中均可写入图片到系统剪贴板。

// 浏览器:与 copyImage 相同
NowClipboard.writeImage('https://example.com/photo.png')
  .then(function (blob) { console.log('图片已写入:', blob.size); });

// 浏览器:Canvas / img 元素
NowClipboard.writeImage(document.querySelector('#myCanvas'));

// Node.js:从 Buffer 写入
var fs = require('fs');
var imgBuffer = fs.readFileSync('/path/to/image.png');
NowClipboard.writeImage(imgBuffer).then(function () {
  console.log('图片已写入系统剪贴板');
});

// Node.js:从文件路径写入
NowClipboard.writeImage('/path/to/image.png').then(function () {
  console.log('图片已写入');
});

Node.js writeImage 系统命令:

| 操作系统 | 命令 | 备注 | |---------|------|------| | Windows | PowerShell Clipboard.SetImage() | 通过 Base64 传递图片数据 | | macOS | pbcopy | 支持 PNG 格式 | | Linux | xclip -t image/png | 需安装 xclip |

15. 多格式写入(writeFormats)

一次写入多种 MIME 格式到剪贴板。需要 HTTPS + 现代浏览器(支持 ClipboardItem API)。

// 同时写入纯文本和 HTML
NowClipboard.writeFormats({
  'text/plain': 'Hello World',
  'text/html': '<b>Hello</b> World'
}).then(function (formats) {
  console.log('已写入格式:', Object.keys(formats));
});

// 写入文本 + 图片
NowClipboard.writeFormats({
  'text/plain': '图片描述',
  'image/png': imageBlob
});

// 自定义 MIME 类型
NowClipboard.writeFormats({
  'text/csv': 'name,age\nAlice,30',
  'application/json': '{"name":"Alice","age":30}'
});

16. 剪贴板历史(History)

自动记录剪贴板内容变更,支持搜索和持久化存储。

// 创建历史实例
var history = new NowClipboard.History({
  maxSize: 50,           // 最大条目数(默认 50)
  storage: 'localStorage', // 存储方式:'memory' | 'localStorage' | 'sessionStorage'
  storageKey: 'my_history', // 存储键名(默认 'nowclipboard_history')
  pollInterval: 1000     // 轮询间隔 ms(默认 1000)
});

// 开始监听
history.start();

// 获取所有历史
history.list(); // [{ text: '...', timestamp: 1234567890, type: 'text' }, ...]

// 搜索历史
history.search('关键词'); // 返回匹配的条目

// 获取最近一条
history.latest(); // { text: '...', timestamp: ..., type: 'text' }

// 当前条目数
history.size(); // 5

// 清空历史
history.clear();

// 停止监听(保留历史数据)
history.stop();

// 销毁实例(清空历史 + 停止监听)
history.destroy();

⚠️ History 使用 onChange 轮询监听剪贴板,仅浏览器环境可用。localStorage / sessionStorage 持久化需要页面在 HTTP/HTTPS 下访问。

17. 跨标签页同步(onSync)

基于 BroadcastChannel API,同一来源下的多个标签页自动同步剪贴板操作。

// 启动同步(默认自动同步 copy/cut 操作)
var sync = NowClipboard.onSync({
  channel: 'nowclipboard', // BroadcastChannel 名称(默认 'nowclipboard')
  autoSync: true           // 自动同步 copy/cut(默认 true)
});

// 监听其他标签页的复制操作
sync.addListener(function (data) {
  console.log('其他标签页复制了:', data.type, data.text);
  // data.type: 'copy' | 'cut' | 自定义
  // data.text: 复制的文本
  // data.timestamp: 时间戳
});

// 广播自定义消息
sync.broadcast({ type: 'custom', message: 'Hello from Tab A' });

// 移除监听
sync.removeListener(myCallback);

// 销毁同步实例(恢复原始 copy/cut 方法)
sync.destroy();

⚠️ onSync 仅在浏览器环境且支持 BroadcastChannel 的浏览器中可用(Chrome 54+、Firefox 38+、Safari 15.4+)。不支持时会静默返回空操作对象。

API 参考

构造函数

new NowClipboard(trigger, [options])

| 参数 | 类型 | 说明 | |------|------|------| | trigger | string \| Element \| NodeList | CSS 选择器、DOM 元素或元素集合 | | options.action | Function | (trigger) => 'copy' \| 'cut' | | options.target | Function | (trigger) => Element | | options.text | Function | (trigger) => string | | options.container | Element | 容器元素,默认 document.body | | options.retries | number | 最大重试次数,默认 2 | | options.retryDelay | number | 基础重试延迟 ms,默认 100(指数退避) | | options.timeout | number | 超时 ms,默认 0(不超时) | | options.signal | AbortSignal \| null | 取消操作的信号 |

实例方法

| 方法 | 说明 | |------|------| | .on(event, handler) | 注册事件监听(destroy 后调用会抛错) | | .once(event, handler) | 注册一次性事件监听(destroy 后调用会抛错) | | .off(event, handler) | 移除事件监听(destroy 后调用会抛错) | | .destroy() | 销毁实例,移除所有事件监听和 DOM 绑定 |

静态方法

| 方法 | 返回值 | 说明 | |------|--------|------| | NowClipboard.copy(text, [options]) | Promise<string> | 复制文本到剪贴板 | | NowClipboard.write(text, [options]) | Promise<string> | 写入文本到剪贴板(copy 的别名) | | NowClipboard.cut(element, [options]) | Promise<string> | 剪切元素内容(仅浏览器) | | NowClipboard.read([options]) | Promise<string> | 读取剪贴板文本 | | NowClipboard.readRich([options]) | Promise<{text, html, images}> | 读取剪贴板富内容(文本+HTML+图片,仅浏览器) | | NowClipboard.writeImage(source, [options]) | Promise<Blob> | 写入图片到剪贴板(浏览器 + Node.js) | | NowClipboard.writeFormats(formats, [options]) | Promise<FormatsMap> | 一次写入多种 MIME 格式(仅浏览器) | | NowClipboard.copyImage(source, [options]) | Promise<Blob> | 复制图片(支持 Blob/File/Img/Canvas/URL) | | NowClipboard.copyBlob(blob, [mimeType], [options]) | Promise<Blob> | 复制任意 Blob 到剪贴板 | | NowClipboard.copyRich(options) | Promise<{text, html}> | 复制富文本(HTML + 纯文本) | | NowClipboard.onPaste(target, callback) | { destroy } | 监听粘贴事件(仅浏览器) | | NowClipboard.onChange(callback, [interval]) | { destroy } | 监听剪贴板变更(仅浏览器,轮询方式) | | NowClipboard.onSync([options]) | SyncInstance | 跨标签页同步(仅浏览器,BroadcastChannel) | | NowClipboard.queryPermission(name) | Promise<{ state }> | 查询剪贴板权限('read'/'write') | | NowClipboard.checkSupport([actions]) | boolean | 检测环境是否支持剪贴板操作 | | NowClipboard.History | ClipboardHistory | 剪贴板历史类 |

RetryOptions 配置

| 选项 | 类型 | 默认值 | 说明 | |------|------|--------|------| | retries | number | 2 | 最大重试次数 | | retryDelay | number | 100 | 基础重试延迟 ms(指数退避) | | timeout | number | 0 | 超时 ms(0 = 不超时) | | signal | AbortSignal \| null | null | 取消操作的信号 |

事件

success 事件

复制/剪切操作成功时触发。

clipboard.on('success', function (e) {
  e.action;          // 'copy' 或 'cut'
  e.text;            // 复制的文本内容
  e.trigger;         // 触发操作的 DOM 元素
  e.clearSelection(); // 清除页面选区
});

error 事件

操作失败时触发。

clipboard.on('error', function (e) {
  e.action;          // 'copy' 或 'cut'
  e.trigger;         // 触发操作的 DOM 元素
  e.error;           // Error 对象,包含失败原因
  e.clearSelection(); // 清除页面选区
});

HTML 属性

| 属性 | 说明 | 示例 | |------|------|------| | data-nc-text | 指定要复制的文本 | data-nc-text="复制我" | | data-nc-target | 指定目标元素的 CSS 选择器 | data-nc-target="#input1" | | data-nc-action | 操作类型:copy(默认)或 cut | data-nc-action="cut" | | data-nc-html | 启用富文本复制模式 | data-nc-html="true" |

降级策略

库会自动按以下顺序尝试最佳方案:

1. navigator.clipboard.writeText()    (HTTPS + 现代浏览器)
       |
       v 失败
2. document.execCommand('copy')       (HTTP + 旧浏览器)
       |
       v 失败
3. child_process (PowerShell/pbcopy/xclip)  (Node.js 环境)
       |
       v 失败
4. 抛出错误,触发 'error' 事件

每层失败后自动重试(默认最多 2 次,指数退避),重试次数、延迟、超时均可配置。支持通过 AbortSignal 取消正在进行的操作。

支持的元素类型

| 元素 | 复制 | 剪切 | |------|------|------| | <input> | 支持 | 支持 | | <textarea> | 支持 | 支持 | | <select> | 支持 | -- | | contenteditable 元素 | 支持 | 支持 | | 普通元素(div, span 等) | 支持 | -- |

浏览器兼容性

NowClipboard 优先使用现代 Clipboard API,并自动降级到 execCommand 以支持旧版浏览器。

💡 如果需要支持旧版浏览器,NowClipboard 会自动降级到 execCommand 方案。你只需在 error 事件中提示用户手动 Ctrl+C 即可。

与 ClipboardJS 的区别

| 对比项 | ClipboardJS | NowClipboard.js | |--------|-------|-----------| | 复制方式 | 仅 execCommand | Clipboard API + execCommand 降级 | | 图片复制 | 不支持 | 支持(Blob/File/Img/Canvas/URL/data: URL) | | 富文本复制 | 不支持 | 支持(HTML + 纯文本同时复制) | | 读取剪贴板 | 不支持 | 支持(浏览器 + Node.js) | | 富内容读取 | 不支持 | 支持(readRich:文本+HTML+图片) | | 粘贴监听 | 不支持 | 支持(onPaste + 自动解析) | | 变更监听 | 不支持 | 支持(onChange 轮询检测) | | 多格式写入 | 不支持 | 支持(writeFormats 一次写入多种 MIME) | | Node.js 写入图片 | 不支持 | 支持(writeImage Buffer/文件路径) | | 剪贴板历史 | 不支持 | 支持(History 类 + 搜索 + 持久化) | | 跨标签页同步 | 不支持 | 支持(onSync BroadcastChannel) | | 权限检测 | 不支持 | 支持(queryPermission) | | 异步 | 同步 | Promise-based | | 重试 | 无 | 可配置重试 + 指数退避 + 超时 + AbortSignal | | Node.js | 不支持 | 支持 (Win/Mac/Linux) | | TypeScript | 无类型定义 | 内置 .d.ts 类型定义 | | ESM | 不支持 | 支持(ESM + UMD 双格式) | | iOS Safari | 未适配 | 自动降级适配 | | 代码 | 压缩混淆 | 可读、带注释 | | 销毁 | 基础 | 完善(防内存泄漏 + destroy 后保护) |

完整示例

交互式演示

项目包含一个交互式演示页面 demo.html,可在线体验所有功能:

# 启动本地服务器(推荐,剪贴板 API 需要 HTTP/HTTPS 环境)
npx serve .
# 然后访问 http://localhost:3000/demo.html

⚠️ 不推荐直接用 file:// 协议打开,浏览器不会为本地文件持久化剪贴板读取权限,会导致反复弹出授权弹窗。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>NowClipboard Demo</title>
</head>
<body>
  <input id="source" value="这是要复制的内容" style="width: 300px;">
  <button class="copy-btn" data-nc-target="#source">复制输入框</button>
  <button class="copy-btn" data-nc-text="直接复制这段文字">复制文本</button>
  <p id="result"></p>

  <script src="NowClipboard.js"></script>
  <script>
    var clipboard = new NowClipboard('.copy-btn');
    var result = document.getElementById('result');

    clipboard.on('success', function (e) {
      result.textContent = '复制成功: ' + e.text;
      e.clearSelection();
    });

    clipboard.on('error', function (e) {
      result.textContent = '复制失败: ' + e.error.message;
    });
  </script>
</body>
</html>

许可证

MIT