JavaScript实现点击复制功能具体代码(JS访问剪贴板相关)
作者:努力的小朱同学
一、具体代码
网页前端开发中有时会出现这样的场景:让用户点击某个按钮,然后就能直接复制对应的文本内容,让用户可以将文本内容粘贴到想要粘贴的地方,常用于分享功能模块中。如果想要实现这种效果就需要我们去访问用户的剪贴板,然后把想要复制的内容写入其中即可,本文主要讲解两种解决方案: document.execCommand() 和 Clipboard 。
先上代码:
?为了同时兼容新旧浏览器(IE!),我们一般采取下面的方式:
// 复制文本内容
function copyContent (content) {
// 复制结果
let copyResult = true
// 设置想要复制的文本内容
const text = content || '让我们一起快乐的敲代码吧~';
// 判断是否支持clipboard方式
if (!!window.navigator.clipboard) {
// 利用clipboard将文本写入剪贴板(这是一个异步promise)
window.navigator.clipboard.writeText(text).then((res) => {
console.log('复制成功');
// 返回复制操作的最终结果
return copyResult;
}).catch((err) => {
copyResult = false
console.log('复制失败', err);
// 返回复制操作的最终结果
return copyResult;
})
} else {
// 不支持clipboard方式 则采用document.execCommand()方式
// 创建一个input元素
let inputDom = document.createElement('textarea');
// 设置为只读 防止移动端手机上弹出软键盘
inputDom.setAttribute('readonly', 'readonly');
// 给input元素赋值
inputDom.value = text;
// 将创建的input添加到body
document.body.appendChild(inputDom);
// 选中input元素的内容
inputDom.select();
// 执行浏览器复制命令
// 复制命令会将当前选中的内容复制到剪切板中(这里就是创建的input标签中的内容)
// Input要在正常的编辑状态下原生复制方法才会生效
const result = document.execCommand('copy')
// 判断是否复制成功
if (result) {
console.log('复制成功');
} else {
console.log('复制失败');
copyResult = false
}
// 复制操作后再将构造的标签 移除
document.body.removeChild(inputDom);
// 返回复制操作的最终结果
return copyResult;
}
}二、剪贴板
? 剪贴板是用于短期数据存储或者转移的数据缓存区,数据转移可以发生在不同的文档或应用程序之间。剪贴板常常实现为一个匿名的、临时的数据缓存,有时也叫做粘贴缓存,可由绝大部分位于已定义应用程序接口的环境中的程序访问。
三、Clipboard
1、简介
? Clipboard API 提供了响应剪贴板命令和异步读写系统剪贴板的能力,该API是用来取代 document.execCommand() 这种剪贴板访问方式的。但是该API需要通过 PerMissions API获取用户授予的权限( "clipboard-read" 或 "clipboard-write" )之后,才能访问剪贴板,如果用户拒绝授予相应权限,则无法访问剪贴板,调用 Clipboard 对象的方法就会失败。而且该API仅在一些安全上下文环境中可用(HTTPS、localhost、127.0.0.1等),我们可以通过 window.isSecureContext 的返回值来判断当前环境是否为安全上下文环境。

? 我们可以通过 window.navigator.permissions.query({name: "clipboard-read"}) 和 window.navigator.permissions.query({name: "clipboard-write"}) 来判断当前网页是否拥有读写剪贴板的权限(Firefox不支持!)。
? 该API在 Window.navigator 接口上添加了只读属性 clipboard ,该属性返回一个可以读写剪切板内容的 Clipboard 对象,我们前端大多是通过 window.navigator.clipboard 来访问剪贴板。
? 由于该API是一个较新的API,而且涉及的安全问题和技术复杂性太多,所以浏览器兼容性相对差一点(不支持IE):
浏览器兼容性(Navigator.clipboard):

2、Clipboard
? 该接口实现了 Clipboard API,用于读写系统剪贴板上的文本和数据的接口,前端规范称其为异步剪贴板API(Async Clipboard API),因为该API下的所有方法都是异步的,它们会返回一个 Promise 对象,操作成功后调用 resolve() ,操作失败后调用 reject() 。
相关方法:
① read()
? 该方法用于从系统剪贴板中读取任意数据的副本(文本、图片等),返回一个 Promise 对象,在经过异步数据检索之后, Promise 返回一个包含相关数据的 ClipboardItem 对象的数组,该数组含有两个数据对象,第一个对象中仅包含剪贴板中的文本数据,第二个对象中包含剪贴板中的所有内容数据。
? 该方法必须在网页获取焦点时,才能正常调用,否则会报错。而且该方法不能在JS中直接调用,只能在处理用户行为(点击等交互行为)时才能正常调用,否则会报错。
? 如果系统剪贴板中的内容是复制的系统本地的文件,则通过该方法只能访问到文件名,而无法访问到文件本身的内容。如果我们是复制的系统本地文件中的内容,并包含文本和图片,则该方法能正常获取到文本信息,但图片无法被获取到。
② readText()
? 该方法从系统剪贴板读取中文本数据的副本,返回一个 Promise 对象,在经过异步数据检索之后, Promise 返回一个包含相关文本数据的 String 字符串数据。
? 该方法必须在网页获取焦点时,才能正常调用,否则会报错。但是与 read() 不同的是,该方法可以在JS中直接调用,不需要等待用户行为。
? 如果系统剪贴板中的内容是复制的系统本地的文件,则通过该方法可以访问到文件名。如果我们是复制的系统本地文件中的内容,并包含文本和图片,则该方法只能获取到其中文本信息。
案例代码:
<button onclick="clickRead()">点击访问剪贴板</button>
<p>我想调用Clipboard API来读取剪贴板信息</p>
<p>我想2342342342432</p>
<img src="./image/img.png" alt="">
<div>23423423422</div>
<script>
// 在刚进入页面时,先尝试获取剪贴板的内容
window.navigator.clipboard.read().then((res) => {
console.log('read--res-----', res);
}).catch((err) => {
console.log('read--err-----', err);
})
// 在刚进入页面时,先尝试获取剪贴板的文本内容
window.navigator.clipboard.readText().then((res) => {
console.log('readText--res-----', res);
}).catch((err) => {
console.log('readText--err-----', err);
})
// 用户点击按钮事件
function clickRead () {
// 再次尝试获取剪贴板的内容 promise异步操作
window.navigator.clipboard.read().then((res) => {
console.log('用户点击-read--res-----', res);
res[0].types.forEach((type, index) => {
// 通过getType读取剪贴板中对应的数据内容 并返回相应blob对象
res[0].getType(type).then(res => {
console.log('blob--', res);
let reader = new FileReader();
// 为了方便查看 将bolb转为base64 (异步操作)
reader.readAsDataURL(res);
// 转换成功
reader.onload = () => {
if (index === 0) {
console.log('用户剪贴板中的所有文本内容转换成的base64--', reader.result);
} else
if (index === 1) {
console.log('用户剪贴板中的所有数据内容内容转换成的base64--', reader.result);
}
};
});
})
}).catch((err) => {
// 读取失败的情况
console.log('用户点击-read--err-----', err);
})
// 在用户点击事件中 再次尝试获取剪贴板的文本内容
window.navigator.clipboard.readText().then((res) => {
// 读取成功的情况
console.log('用户点击-readText--res-----', res);
}).catch((err) => {
// 读取失败的情况
console.log('用户点击-readText--err-----', err);
})
}
</script>页面未获取剪贴板访问权限时:

有权限但页面未获取焦点时:

有权限且页面获取焦点时:

有权限且页面获取焦点,并触发用户行为:

文本内容base64查看:

所有内容base64查看:

③ write()
? 该方法用于写入任意数据至系统剪贴板,参数为一个 ClipboardItem 对象数组(但每次只能包含一个 ClipboardItem 对象),里面包含了要写入剪贴板的数据,返回值为一个 Promise 对象,经过异步操作之后,返回执行结果。
? 目前主流浏览器都支持写入的 MIME 数据类型有: text/plain 、 text/html 、 image/png 、 text/uri-list 。
④ writeText()
? 该方法用于写入文本数据至系统剪贴板,参数为一个 String 字符串,表示要写入剪贴板的文本数据,返回值为一个 Promise 对象,经过异步操作之后,返回执行结果。
案例代码:
<!-- 点击选择文件写入到剪贴板 -->
<input type="file" onchange="clickWrite(event)">
<script>
// 在刚进入页面时,先尝试向剪贴板写入内容
// 定义数据类型
const type = "text/plain";
// 创建一个blob对象
const blob = new Blob(['我是要通过write()写入剪贴板的内容1111'], { type });
// 创建一个ClipboardItem对象数组
const data = [new ClipboardItem({ [type]: blob })];
console.log('data--', data);
// 将数据写入剪贴板
window.navigator.clipboard.write(data).then((res) => {
console.log('write--res-----', res);
// 输出剪贴板中的内容
window.navigator.clipboard.readText().then((res) => {
console.log('readText--res-----', res);
}).catch((err) => {
console.log('readText--err-----', err);
})
}).catch((err) => {
console.log('write--err-----', err);
})
// 因为读写都是异步操作 为了避免两个写操作互相干扰 所以等待1秒后 再尝试向剪贴板写入文本内容
setTimeout(() => {
window.navigator.clipboard.writeText('我是要通过writeText()写入剪贴板的文本内容2222').then((res) => {
console.log('writeText--res-----', res);
// 输出剪贴板中的内容
window.navigator.clipboard.readText().then((res) => {
console.log('readText--res-----', res);
}).catch((err) => {
console.log('readText--err-----', err);
})
}).catch((err) => {
console.log('writeText--err-----', err);
})
}, 1000)
// 用户选择图片写入剪贴板事件
function clickWrite (e) {
console.log('file--', e.target.files[0]);
// 定义数据类型
const type = "image/png";
// 创建一个ClipboardItem对象数组
const data = [new ClipboardItem({ [type]: e.target.files[0] })];
console.log('data--', data);
// 将数据写入剪贴板
window.navigator.clipboard.write(data).then((res) => {
console.log('write--res-----', res);
// 输出剪贴板中的内容
window.navigator.clipboard.read().then((res) => {
console.log('read--res-----', res);
}).catch((err) => {
console.log('read--err-----', err);
})
}).catch((err) => {
console.log('write--err-----', err);
})
}
</script>执行结果:

3、ClipboardEvent
? 该接口继承了 Event 接口,提供了有关系统剪贴板信息修改的事件,即 cut 、 copy 、 paste 事件,前端规范称其为剪贴板事件(Clipboard Event API)。
? 我们可以通过 ClipboardEvent(type[, options]) 构造函数来创建 ClipboardEvent 对象,第一个参数 type ,是一个字符串,表示当前事件类型的名字,可以为: cut 、 copy 、 paste ,大小写敏感;第二个参数 options 是可选的,内包含一个 clipboardData 属性,该属性的值是一个 DataTransfer 对象,包含了剪贴板事件所涉及的数据。
var clipboardEvent = new ClipboardEvent(type[, options]);
// 实例
var clipboardEvent = new ClipboardEvent('paste', {
clipboardData: new DataTransfer()
});? ClipboardEvent.clipboardData 属性保存了一个 DataTransfer 对象,该对象有两个用途:① 用于指定通过 cut 和 copy 事件写入到剪贴板中的数据,通常使用 setData(format,data) 来指定数据。② 用于从 paste 事件中获取想要从剪贴板中读取的数据,通常使用 getData(fomat) 来获取。 fomat 表示数据类型,例如: text/plain 、 text/uri-list 。
案例代码:
var clipboardEvent = new ClipboardEvent('paste', {
clipboardData: new DataTransfer()
});
console.log('clipboardEvent--', clipboardEvent.clipboardData.getData('text/plain'));
clipboardEvent.clipboardData.setData('text/plain', 'Clipboard API来读取剪贴板信息');
console.log('clipboardEvent--', clipboardEvent.clipboardData.getData('text/plain'));执行结果:

4、ClipboardItem
? 该接口表示在使用read()和write()读写剪贴板数据时,单个数据的数据格式,该数据格式中将 MIME 类型作为 key ,将数据作为 value 。
① 创建ClipboardItem对象
? 可通过构造函数 ClipboardItem(data[, options]) 来创建该对象,第一个参数为想要存储的数据,可以为 Blob 、 String 或 Promise (但个人开发发现 file 对象也可以);第二个对象参数表示数据的呈现形式,该对象只包含 presentationStyle 属性,属性值有三种: unspecified 、 inline 和 attachment . 默认值为 unspecified ,但是该属性支持性特别差:Chrome、Edge、Firefox、Opera都不支持该属性, Safari 支持该属性,所以该属性了解即可。
? 我们也可以通过 ClipboardItem.presentationStyle 来获取当前对象的数据呈现形式。
new ClipboardItem(data[, options])
// 实例
const test = new ClipboardItem({ ["text/plain"]: new Blob(['我是小朱同学'], { "text/plain" }) }② 读取ClipboardItem对象中的数据
? 首先我们可以通过 ClipboardItem.types 获取当前 ClipboardItem 对象中所有MIME 类型组成的数组,然后再通过 getType(type) 方法来异步读取对应的数据,返回一个Promise,读取的数据为Blob类型:
ClipboardItem.types.forEach(type => {
ClipboardItem.getType(type).then(res => {
console.log('blob--', res);
})
})二、document.execCommand()
1、简介
? 该方法用来操作当前聚焦的可编辑元素( input 、 textarea )中的内容,例如复制、剪贴、粘贴、删除、文本加粗、插入图片等等效果,有些富文本编辑器组件就是基于该API进行开发。而且该API的兼容性很好,可以兼容到 IE6 及以上。该API已经不推荐使用了,因为现在该API已经被 Clipboard 全面替代,虽然目前多数主流浏览器还支持使用,但随时有可能被完全弃用。
浏览器兼容性:

2、基本语法
cosnt result = document.execCommand(aCommandName[,aShowDefaultUI,aValueArgument])
参数:
? ① aCommandName :一个命令字符串,表示要执行操作的名称,常用的有: copy 、 cut 、 paste 、 bold 等等,具体可查询:execCommand。
? ② aShowDefaultUI :一个布尔值,表示是否展示用户界面,一般为 false (Firefox不支持)。
? ③ aValueArgument :第一个参数中的某些命令需要的额外参数,默认为 null ,例如: insertImage 需要提供插入 image 的 url 。
返回值:
? ① 一个 Boolean :表示要执行操作是否执行成功( true ),若为 false ,则表示操作不被支持或操作失败。
3、基本使用
function copyInputContent () {
// 设置想要复制的文本内容
const text = '让我们一起快乐的敲代码吧~';
// 创建一个input元素
let inputDom = document.createElement('textarea');
// 设置为只读 防止移动端手机上弹出软键盘
inputDom.setAttribute('readonly', 'readonly');
// 给input元素赋值
inputDom.value = text;
// 将创建的input添加到body
document.body.appendChild(inputDom);
// 选中input元素的内容
inputDom.select();
// 执行浏览器复制命令
// 复制命令会将当前选中的内容复制到剪切板中(这里就是创建的input标签中的内容)
// Input要在正常的编辑状态下原生复制方法才会生效
const result = document.execCommand('copy')
// 复制操作后再将构造的标签 移除
document.body.removeChild(inputDom);
}三、参考文档
总结
到此这篇关于JavaScript实现点击复制功能(JS访问剪贴板相关)的文章就介绍到这了,更多相关JS点击复制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
