剪贴板复制粘贴操做汇总

剪贴板

在前端平常开发中,对剪贴板相关的操做相对较少。但针对某些特定的应用场景,又是必不可少会用到的。好比:富文本编辑器开发、ctrl + v 上传图片、支付宝红包口令自动复制(典型被玩坏儿了的用途)javascript

剪贴板操做途径

剪贴板事件

操做剪贴板,最基础的方式为监听剪贴板事件。出于兼容性考虑,通常都只在剪贴板事件处理函数中访问 clipboardData ,非 IE 浏览器读数据只能在 onpaste 事件时可用。要使用剪贴板事件读写数据,就必须得用户主动使用快捷键或者右键菜单。因此监听板事件的主要应用场景是用户触发后对数据进行拦截处理。html

document.execCommand

document.execCommand() 方法用于操纵可编辑区域的内容,例如最经常使用的 'copy' 命令可将选择区域的内容复制到剪贴板中,配合 window.getSelection() 方法就能够实现自动选择内容区域并写入内容到剪贴板。clipboard.js 库及红包口令自动复制主要就经过此方法实现的。前端

此方法也有一些问题:java

  • Chrome \ Safari 不支持 'paste' 命令
  • Chrome 不能直接在后台调用 'copy' 命令,需用户点击触发
  • IE 可直接在后台调用和点击触发 'copy' 命令,但会出现权限提示

Asynchronous Clipboard API

看过上面的介绍,你会发现,操做剪贴板到处受限,并且迂回曲折,更困难的是有些功能是没法实现的。但不能否认,形成这一困惑很大一部分缘由是安全考虑。node

试想一下,当你浏览网页,点了下页面或者按钮,就复制了支付宝红包口令,会怎样?呃,还能接受?那么 'rm -rf /' 呢?(我用 Windows,我怕啥ios

而作为 Clipboard API 新增内容的 Asynchronous Clipboard API 及 Clipboard Permissions API 就是为了解决上述问题而来的,专治各类迂回曲折及安全风险。截至目前(2018.03),Chrome 66 实现了部分功能,预测将来会有变化,本文不作详细介绍。暂概括特色以下:git

  • HTTPS 下才能调用
  • 页面处于活动选项卡才能调用
  • 基于 Promise,便于异步操做和错误处理
  • 实现了编程方式的粘贴(读)和复制(写)
  • 粘贴(读)和复制(写)权限已添加到 Permissions API 中 ,操做须要用户受权
  • Clipboard Permissions API 目前仅适用于 Asynchronous Clipboard API。根据规范,将来会添加到全部 Clipboard API 中

处理粘贴 ( paste )

对于粘贴,目前普遍支持的仅有快捷键及右键菜单触发,而 IE 支持的编程方式使用场景很少,这里不作介绍。github

纯文本或带格式文本

对纯文本的拦截编程

El.addEventListener('paste', event => {
    event.preventDefault();
    let clipboardData = event.clipboardData || window.clipboardData, // IE 兼容
        plainText = clipboardData.getData('text');  // 无格式文本
    
    // ... 对 plainText 进行一系列处理操做
    
    document.execCommand('insertText', false, plainText);  // 插入无格式文本
    document.execCommand('paste', false, plainText);  // IE 兼容
})
复制代码

如需对有格式文本进一步处理,可用如下方法转换为 DOM 结构,再进行操做。(IE 浏览器没法得到 'text/html' 因此没法实现下面的功能)api

/* 仍在上述事件处理函数中,下面均省略 */
    let plainHTML = clipboardData.getData('text/html'),   // 有格式文本
        domContainer = document.createElement('div');
    domContainer.innerHTML = plainHTML;
    
    // ... 对 domContainer 进行一系列处理操做
    
    El.innerHTML = domContainer.innerHTML; // 使用 innerHTML 方式总体插入
    El.appendChild(nodeOfDomContainer); // 只插入其中某个节点
复制代码

图片

如 DOM 结构中含有图片标签,可考虑上传图片至服务器中,而后将其 src 替换为服务器返回的地址。

如复制的是单个图片(例如 word 中复制过来的),可使用下述方法获得图片的 DataURL,再上传。(IE 浏览器粘贴图片会自动生成带 DataURL 的图片标签,因此不须要下述方法)

let items = clipboardData.items;
    for (let i = 0; i < items.length; i++) {
        let item = items[i];
        if (/image/.test(item.type)) {
            let file = item.getAsFile(), // 获得文件对象
                reader = new FileReader();
            reader.onload = function() {
                upload(reader.result) // 上传图片,伪代码
            }
            reader.readAsDataURL(file); // 读取为 DataURL / Base64
        }
    }
复制代码

处理复制 ( copy )

快捷键及右键菜单触发

常见应用场景是拦截复制操做,对复制内容加工后再写入剪贴板,例如在知乎复制大段文本后加入版权信息。

El.addEventListener('copy', event => {
    event.preventDefault();
    let clipboardData = event.clipboardData || window.clipboardData,
        text = window.getSelection().toString();
    
    // ... 对 text 进行一系列处理操做
    
    clipboardData.setData('text/plain', text); // 将处理好的 text 写入剪贴板
    clipboardData.setData('text', text); // IE 兼容
})
复制代码

编程式复制

虽是编程式复制,但没法作到彻底自动复制,须要用户先触发 点击 事件。clipboard.js 库及红包口令自动复制(在 document 上监听 click 事件)主要就经过此方法实现的。

固定内容

Button.addEventListener('click', event => {
    let sometext = '红包码 xxxxxx',
        hiddenInput = document.createElement('input');
    hiddenInput.value = sometext;
    hiddenInput.setAttribute('readonly', '');
    hiddenInput.style.position = 'absolute';
    hiddenInput.style.left = '-9999px';
    document.body.appendChild(hiddenInput);
    hiddenInput.select();
    hiddenInput.setSelectionRange(0, hiddenInput.value.length); // ios
    document.execCommand('copy');
    document.body.removeChild(hiddenInput);
})
复制代码

复制某个元素内的文本

Button.addEventListener('click', event => {
    let someElement = document.getElementById('someelement'),
        selection = window.getSelection(),
        range = document.createRange();
    range.selectNodeContents(element);
    selection.removeAllRanges();
    selection.addRange(range);
    document.execCommand('copy');
})
复制代码

能够发现,目前对剪贴板的操做真是千奇百怪,但愿新的 API 快快成为现实吧(作梦)!

参考

[1] Clipboard API and events | w3c

[2] clipboard.js | Github

[3] 利用 javascript 实现富文本编辑器 | 掘金

[4] 富文本编辑器初探 | 掘金

[5] JavaScript复制内容到剪贴板 | 掘金