在学习 Clipboard API 前先看下 MDN 对它的解释:
剪贴板 Clipboard API 提供了响应剪贴板命令(剪切、复制和粘贴)与异步读写系统剪贴板的能力。从权限 Permissions API 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取或更改剪贴板内容。
该 API 被设计用来取代使用 document.execCommand() 的剪贴板访问方式。
可以从 MDN 中的介绍可以看出,它是一个针对剪切板处理而产生的 API,它有四个方法且都是异步的 ( Returns Promise ),promise 的处理结果就是用户是否同意你访问用户的剪切板。
我用的浏览器是谷歌最新的浏览器,每个浏览器的效果与处理函数会有所不同。
clipboard.read()
该方法返回一个 Promise,里面保存着一份剪切板内容的副本,可以时一切数据类型,可以时图片等。
语法:
const promise = navigator.clipboard.read();
也可以直接处理 Promise,通过 .then ...catch 链式的形式
示例:
需求: 当用户一进入页面,将用户上一次剪切版的内容展示在页面上。
代码:
<div id="display"></div>
<script type="text/javascript">
const oDiv = document.getElementById('display')
window.onclick = async () => {
navigator.clipboard.read().then(clipboardItems => {
let reader = new FileReader() // 文件解码器
console.log(clipboardItems)
clipboardItems[0].getType('text/plain').then(data => {
// 二进制数据( Blob ) data
reader.onload = e => { // 函数完成后触发的事件
// 对二进制编码后的结果
oDiv.innerText = e.target.result
}
reader.readAsText(data) // 是一个异步函数
})
})
}
</script>
read() 返回的 Promise 中保存的是一个 clipboardItem[] 数组,MDN 对它的解释是:
剪贴板API的ClipboardItem接口表示通过剪贴板API读取或写入数据时使用的单个项格式。
可以通过它的 getType () 方法返回的 ( Promise ) 可以获取到剪切板的二进制数据(Blob),通过 FileReafer() 文件解码器对二进制数据进行处理。
下面我来说下,我踩的坑。上面的例子中你应该或多或少有一个疑问,为什么是绑 window.onclick 的点击事件,而不是 window.onload 呢?这里就是第一个坑,如果使用 window.onload 控制台会报个错:
Uncaught (in promise) DOMException: Must be handling a user gesture to use custom clipboard
必须处理用户手势才能使用自定义剪贴板,也就是需要页面与用户有交互才行
第二个坑,按照 MDN 中的文档,clipboard.read() 方法可以获取任何数据类型,可我并没有获取到除文本类型以外的数据。查资料也没有什么文档有用(如果有知道的可以私聊我,找资料找的烦死了...)。
clipboard.readText()
Clipboard 接口的 readText()
方法解析系统剪贴板的文本内容返回一个Promise 。这个方法比 read() 方法方便很多,不过只可以读取文本信息。
需求:与上个例子一致。
代码:
<div id="display"></div>
<script type="text/javascript">
window.onload = () => {
const oDiv = document.getElementById('display')
navigator.clipboard.readText().then(txt => {
oDiv.innerText = txt
})
.catch(err => {
// 用户拒绝处理
})
}
</script>
这个方法不必须要用户与页面产生交互,第一次访问的时候会询问用户是否允许网页访问,更具用户的处理结果返回的 Promise 会以 : 同意( resolve ),拒绝( reject )。
clipboard.write()
Clipboard 的方法 write()
写入图片等任意的数据到剪贴板。这个方法可以用于实现剪切和复制的功能。但是你要提前获取 "Permissions API" 的 "clipboard-write"
权限才能将数据写入到剪贴板。
它有一个参数 DataTransfer 对象包含要写如剪切版的数据。实际上 Chrome 不支持这个对象写入数据,我也查阅过资料,没有一个示例在Chrome 上实现,Chrome上支持 ClipboardItem对象,而且 Chrome 只支持 text/plain 类型的数据写入剪切板,可以写入文件。(可能使用的版本问题!)
需求:选择文件写入剪切板。
代码:
<input type="file" />
<script>
const oFile = document.querySelector('input[type="file"]')
oFile.onchange = function () {
const files = this.files // 获取文件对象数组
if (files.length > 0) { // 判断是否有文件对象
for (let i = 0; i < files.length; i++) {
navigator.clipboard.write([
new ClipboardItem({ // 写入剪切版的内容
[files[i].type] : files[i]
})
])
.then(() => {}) // 成功执行
.catch(err => {}) // 失败,不一定是用户没有授权
}
}
}
</script>
运行打开网页,点击按钮选择一个 .txt 的文件,然后在去粘贴就会发现,粘贴的内容是文本文件的内容。
Uncaught (in promise) DOMException: Type image/jpeg not supported on write.
如果是非 text/plain 的文件对象,会出现类似得异常
clipboard.writeText()
Clipboard 接口的 writeText()
方法可以写入特定字符串到操作系统的剪切板。
需求:当页面加载完成向用户剪切版写入欢迎您。
代码:
<script type="text/javascript">
window.onload = () => {
navigator.clipboard.writeText('欢迎您')
.then(() => {
console.log('success')
})
.catch(err => {
console.log(err)
})
}
</script>
Clipboard Event 事件
ClipboardEvent
接口描述了与修改剪切板相关信息的事件,这些事件包括 剪切cut , 复制copy 和 粘贴paste 事件。clipboardData 属性中的 DataTransfer 中保存着用户 cut,copy,paste 事件的数据。
copy 用户在网页上产生复制事件,会触发。
例如: 阻止用户复制网页内容。
代码:
<script type="text/javascript">
document.addEventListener('copy', e => {
e.preventDefault()
// 后续处理,提示用户等...
})
</script>
cut 剪切事件
当用户在网页上 ctl + x 时或者右键剪切都会触发。
例如: 当用户触发事件后,向剪切板中写入版权信息。
代码:
<script type="text/javascript">
document.addEventListener('cut', e => {
navigator.clipboard.writeText('相关版权不可剪切')
})
</script>
paste 粘贴事件
当用户 ctl+v 或右键粘贴时触发。
需求: 监听 input 的粘贴事件,向粘贴的数据后面追加字符。
代码:
<textarea cols="30" rows="20"></textarea>
<script type="text/javascript">
const oTextArea = document.getElementsByTagName('textarea')[0]
oTextArea.addEventListener('paste', e => {
e.preventDefault()
let txt = e.clipboardData.getData('text/plain') + ",功能由某某提供"
oTextArea.value = txt
})
</script>
阻止默认事件,自定义处理。
到这里 Clipboard WEB API 就基本学习完了,怎么使用,在哪里应用,就看自己的想法了。
最后相下,下面的效果怎么实现。
具体功能上面都有说,利用的就是上面介绍的 API,外层的 div 是用户可以编辑的(contenteditable) 不过,有一弊端,右边的点击上传框也可以删除,而且第一次必须要点按钮上传。我想 bilibili,csdn的上传应该不是使用用户可编辑的形式,不过就当一个练习啦,加深对 clipboard api 的使用。上述示例中还使用到了拖拽API(drop, dragover)。源码放在 http://www.qylove.asia/code/index.tar,如果访问不了,就是服务器到期了。