JavaScript系列:JS实现复制粘贴文字以及图片
一. 基于 Clipboard API 复制文字(推荐)
基本概念
Clipboard API 是一组用于在浏览器中操作剪贴板的 JavaScript API,它允许开发者在网页上读取和写入剪贴板内容,实现复制、剪切和粘贴等功能。Clipboard API 提供了一种在网页上读取和写入剪贴板内容的方式,包括文本、图像和其他类型的数据。Clipboard API 适用于需要与用户剪贴板进行交互的网页应用,如实现一键复制、粘贴功能,或者在用户复制特定内容时自动添加额外信息等。
https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard_API
主要方法
Clipboard API 提供了几个关键的方法来实现剪贴板的读写操作:
- navigator.clipboard.writeText(text):将给定的文本复制到剪贴板。这是一个异步方法,会返回一个 Promise 对象,成功时 Promise 会被解析,失败时会被拒绝。
- navigator.clipboard.readText():从剪贴板读取文本内容。这也是一个异步方法,返回一个 Promise 对象,解析后提供剪贴板中的文本内容。
- navigator.clipboard.write(data):写入更复杂的数据类型到剪贴板,如文件、图像等。data 参数是一个包含 ClipboardItem 对象的数组,每个 ClipboardItem 对象代表剪贴板中的一项数据。这也是一个异步方法,返回一个 Promise 对象。
- navigator.clipboard.read():从剪贴板读取更复杂的数据类型,如文件、图像等。这个方法会返回一个 Promise 对象,解析后提供一个包含 ClipboardItem 对象的数组。
使用限制
- 用户授权:由于安全和隐私的考虑,浏览器在使用 Clipboard API 时通常需要用户授权。例如,在尝试从剪贴板读取或写入数据时,浏览器可能会要求用户明确允许。
- 安全上下文:Clipboard API 只能在安全的环境中操作剪贴板,如 HTTPS 页面、localhost本机下。
- 浏览器兼容性:虽然大多数现代浏览器都支持 Clipboard API,但仍有部分旧版浏览器可能不支持。因此,在使用时需要考虑浏览器的兼容性。
实际应用示例
<template>
<el-button type="primary" @click="handleCopy">复制文本</el-button>
<div>{{ message }}</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const message = ref('复制的内容')
const handleCopy = () => {
navigator.clipboard
.writeText(message.value)
.then(() => {
ElMessage({
message: '复制成功',
type: 'success',
})
})
.catch((err) => {
console.error('复制失败:', err)
ElMessage({
message: '复制失败',
type: 'error',
})
})
}
</script>
二、基于 document.execCommand('copy')
document.execCommand('copy') 是一个在网页上执行复制操作的旧式API,属于 Web API 的一部分,用于在不需要用户交互(如点击或按键)的情况下,通过脚本复制文本到剪贴板。然而,这个API在现代Web开发中已经被视为过时(deprecated),并在许多现代浏览器中受到限制或不再支持,尤其是在没有用户明确交互的情况下。
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
缺陷
- 只能操作input, textarea或具有contenteditable属性的元素
execCommand是同步操作,如果复制/粘贴大量数据,可能会导致页面出现卡顿现象,影响用户体验。- 它只能将选中的内容复制到剪贴板,无法向剪贴板任意写入内容
- 有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。
实际应用示例
<template>
<el-button type="primary" @click="handleCopy2">复制文本2</el-button>
<div>{{ message }}</div>
</template>
<script setup>
import {
copyText,
copyImage,
imageUrlToBase64,
parseBase64,
} from './common/copy'
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const message = ref('复制的内容')
const handleCopy2 = () => {
// 动态创建 textarea 标签
const textarea = document.createElement('textarea')
// 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
textarea.style.opacity = '0'
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = message.value
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
const result = document.execCommand('Copy')
if (result) {
ElMessage({
message: '复制成功',
type: 'success',
})
}
document.body.removeChild(textarea)
}
</script>
说明
clipboard.js 底层也是基于 document.execCommand去实现的
function createFakeElement(value) {
var isRTL = document.documentElement.getAttribute('dir') === 'rtl';
var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS
fakeElement.style.fontSize = '12pt'; // Reset box model
fakeElement.style.border = '0';
fakeElement.style.padding = '0';
fakeElement.style.margin = '0'; // Move element out of screen horizontally
fakeElement.style.position = 'absolute';
fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically
var yPosition = window.pageYOffset || document.documentElement.scrollTop;
fakeElement.style.top = "".concat(yPosition, "px");
fakeElement.setAttribute('readonly', '');
fakeElement.value = value;
return fakeElement;
}
var fakeCopyAction = function fakeCopyAction(value, options) {
var fakeElement = createFakeElement(value);
options.container.appendChild(fakeElement);
var selectedText = select_default()(fakeElement);
command('copy');
fakeElement.remove();
return selectedText;
};
三、复制图片功能
<template>
<el-button type="primary" @click="handleCopyImage">复制图片</el-button>
<div>{{ message }}</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const message = ref('复制的内容')
const handleCopyImage = async () => {
//具体看下面的封装
await copyImage('https://cn.vitejs.dev/logo-with-shadow.png')
ElMessage({
message: '复制成功',
type: 'success',
})
}
</script>
四、封装
/**
* 图片转base64
* @param {string} 图片地址
* @returns
*/
export const imageUrlToBase64 = (imageUrl) => {
return new Promise((resolve, reject) => {
let image = new Image()
image.setAttribute('crossOrigin', 'Anonymous')
image.src = imageUrl
image.onload = function () {
const canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
const context = canvas.getContext('2d')
context.drawImage(image, 0, 0, image.width, image.height)
const base64Str = canvas.toDataURL('image/png')
resolve(base64Str)
}
image.onerror = function (e) {
reject(e)
}
})
}
/**
* 转换base64
* @param {string} base64
* @returns
*/
export function parseBase64(base64) {
let re = new RegExp('data:(?<type>.*?);base64,(?<data>.*)')
let res = re.exec(base64)
if (res) {
return {
type: res.groups.type,
ext: res.groups.type.split('/').slice(-1)[0],
data: res.groups.data,
}
}
}
/**
* 复制文字
* @param {string} text 要复制的文本
* @returns {boolean} true/false
*/
export const copyText = async (text) => {
if (navigator && navigator.clipboard) {
await navigator.clipboard.writeText(text)
return true
}
// 动态创建 textarea 标签
const textarea = document.createElement('textarea')
// 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
textarea.style.opacity = '0'
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = text
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
const result = document.execCommand('Copy')
document.body.removeChild(textarea)
return result
}
/**
* 复制图片
* @param {string} imageUrl 图片地址
* @param {boolean} isBase64 是否是base64
*/
export const copyImage = async (imageUrl, isBase64 = false) => {
let base64Url = ''
if (!isBase64) {
base64Url = await imageUrlToBase64(imageUrl)
} else base64Url = imageUrl
const parsedBase64 = parseBase64(base64Url)
let type = parsedBase64.type
//将base64转为Blob类型
let bytes = atob(parsedBase64.data)
let ab = new ArrayBuffer(bytes.length)
let ua = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ua[i] = bytes.charCodeAt(i)
}
let blob = new Blob([ab], { type })
navigator.clipboard.write([new ClipboardItem({ [type]: blob })])
}
JavaScript系列:JS实现复制粘贴文字以及图片的更多相关文章
- 【javascript】js实现复制、粘贴
使用document.ExecCommand("copy")命令,官方文档,点我. 例如: <!DOCTYPE html> <html> <head& ...
- 使用JS实现复制粘贴功能
使用JS实现复制粘贴功能 如果嵌套太多使用这个: // 複製單號1 // 第一步把這個放到頁面 // <div style="position:absolute; opacity: 0 ...
- js 实现复制粘贴
js 实现复制粘贴 <!DOCTYPE html> <html><head> <meta http-equiv="Content-Type" ...
- 重新想象 Windows 8 Store Apps (40) - 剪切板: 复制/粘贴文本, html, 图片, 文件
[源码下载] 重新想象 Windows 8 Store Apps (40) - 剪切板: 复制/粘贴文本, html, 图片, 文件 作者:webabcd 介绍重新想象 Windows 8 Store ...
- js 实现复制粘贴文本过滤(保留文字和图片)
实现复制粘贴文本过滤(保留文字和图片) demo如下: <head> <meta http-equiv="Content-Type" content=" ...
- 前端复制粘贴文字clipBoard.js的使用
1. vue 中的复制粘贴: <div class="mainTextItem" @click="copyTXTOne" id="copyOn ...
- 通过如何通过js实现复制粘贴功能
在ie中window.clipboardData(剪切板对象)是可以被获取,所以利用这个方法我们可以实现在IE当中复制粘贴的功能,demo如下! <html> <head> & ...
- js实现复制粘贴功能
在项目中使用到复制粘贴功能,虽然网上有很多大牛封装了很多的插件,但是还是想不去使用插件,就像自己来实现这个功能. 另一篇是禁止复制粘贴 前端er怎样操作剪切复制以及禁止复制+破解等 初步想法: 1. ...
- Swift - UIPasteboard剪贴板的使用详解(复制、粘贴文字和图片)
转载自:http://www.hangge.com/blog/cache/detail_1085.html UITextField.UITextView组件系统原生就支持文字的复制,但有时我们需要让其 ...
- vmware12中ubuntu16.10的vmware tools失效,导致不能复制粘贴文字以及自动适应窗口分辨率
问题: 复制命令后,在vmware的ubuntu中粘贴不了,网上说要安装VMWare Tools,但是安装了VMWare Tools 还是不行! 最终找到如下方法: 新安装或异常关机和重新划分分区导致 ...
随机推荐
- gin+MySQL简单实现数据库查询
利用 gin 项目搭建一个简易的后端系统. 一个简易的 HTTP 响应接口 首先在 go 工作区的终端输入这条指令: go get -u github.com/gin-gonic/gin 将 gin ...
- Inno Setup Dependency Installer 安装包 运行环境安装
Download and install any dependency such as .NET, Visual C++ or SQL Server during your application's ...
- C# wpf 实现截屏框实时截屏功能
wpf截屏系列第一章 使用GDI+实现截屏第二章 使用DockPanel制作截屏框第三章 实现截屏框实时截屏(本章)第四章 使用ffmpeg命令行实现录屏 文章目录wpf截屏系列前言一.实现步骤1.获 ...
- 给师妹写的《Java并发编程之线程池十八问》被表扬啦!
写在开头 之前给一个大四正在找工作的学妹发了自己总结的关于Java并发中线程池的面试题集,总共18题,将之取名为<Java并发编程之线程池十八问>,今天聊天时受了学妹的夸赞,心里很 ...
- 「C++」深度分析C++中i++与++i的区别
大家好,我是Charzie.在C++编程中,i++和++i是两个常见的自增运算符,用于将变量的值增加1(有时与i+=1效果一样).然而,虽然它们的功能看似相似,但在实际使用中却存在显著的区别.本博客将 ...
- echarts做饼图
今天记录下echarts做饼图 父组件 <el-card style="height:600px ;margin-top:20px" v-loading="card ...
- 操作标签的属性和属性值 table表格
// 操作标签的属性和属性值 // 特殊的属性 // 可以直接通过 点语法或者[]语法来操作的属性 // id 和 class ...
- Linux扩展篇-shell编程(五)-流程控制(三)-for语句
基本语法: 格式一 for(( 初始值; 循环控制条件; 变量变化)) do statements done 格式二 for 变量 in 值1 值2 值3 ... do statements done ...
- 关于 Elasticsearch 不同分片设置的压测报告
摘要 为了验证当前集群经常出现索引超时以及请求拒绝的问题,现模拟线上集群环境及索引设置,通过压测工具随机生成测试数据,针对当前的 850 个分片的索引,以及减半之后的索引,以及更小分片索引的写入进行压 ...
- 记一次 .NET某工厂报警监控设置 崩溃分析
一:背景 1. 讲故事 前些天有位朋友在微信上丢了一个崩溃的dump给我,让我帮忙看下为什么出现了崩溃,在 Windows 的事件查看器上显示的是经典的 访问违例 ,即 c0000005 错误码,不管 ...