JavaScript系列:JS实现复制粘贴文字以及图片

news/2024/11/17 14:48:08/文章来源:https://www.cnblogs.com/vic-tory/p/18304227

目录
  • 一. 基于 Clipboard API 复制文字(推荐)
    • 基本概念
    • 主要方法
    • 使用限制
    • 实际应用示例
  • 二、基于 document.execCommand('copy')
    • 缺陷
    • 实际应用示例
    • 说明
  • 三、复制图片功能
  • 四、封装

一. 基于 Clipboard API 复制文字(推荐)

基本概念

Clipboard API 是一组用于在浏览器中操作剪贴板的 JavaScript API,它允许开发者在网页上读取和写入剪贴板内容,实现复制、剪切和粘贴等功能。Clipboard API 提供了一种在网页上读取和写入剪贴板内容的方式,包括文本、图像和其他类型的数据。Clipboard API 适用于需要与用户剪贴板进行交互的网页应用,如实现一键复制、粘贴功能,或者在用户复制特定内容时自动添加额外信息等。

https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard_API

主要方法

Clipboard API 提供了几个关键的方法来实现剪贴板的读写操作:

  1. navigator.clipboard.writeText(text):将给定的文本复制到剪贴板。这是一个异步方法,会返回一个 Promise 对象,成功时 Promise 会被解析,失败时会被拒绝。
  2. navigator.clipboard.readText():从剪贴板读取文本内容。这也是一个异步方法,返回一个 Promise 对象,解析后提供剪贴板中的文本内容。
  3. navigator.clipboard.write(data):写入更复杂的数据类型到剪贴板,如文件、图像等。data 参数是一个包含 ClipboardItem 对象的数组,每个 ClipboardItem 对象代表剪贴板中的一项数据。这也是一个异步方法,返回一个 Promise 对象。
  4. 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 iOSfakeElement.style.fontSize = '12pt'; // Reset box modelfakeElement.style.border = '0';fakeElement.style.padding = '0';fakeElement.style.margin = '0'; // Move element out of screen horizontallyfakeElement.style.position = 'absolute';fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position verticallyvar 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 = imageUrlimage.onload = function () {const canvas = document.createElement('canvas')canvas.width = image.widthcanvas.height = image.heightconst 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 = imageUrlconst 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 })])
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/744365.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据分享|R语言决策树和随机森林分类电信公司用户流失churn数据和参数调优、ROC曲线可视化|附代码数据

原文链接:http://tecdat.cn/?p=26868 最近我们被客户要求撰写关于电信公司用户流失的研究报告,包括一些图形和统计输出。 在本教程中,我们将学习覆盖决策树和随机森林。这些是可用于分类或回归的监督学习算法 下面的代码将加载本教程所需的包和数据集。 library(tidyverse…

vue项目中使用axios(自用)

————流程参考在vscode的集成终端中输入npm install axios回车安装重启项目(重新运行) 在script中导入axiosimport axios from axios; 在default中的data同级mounted()中按如下获取数据mounted(){// 发送异步请求,获取数据// 输入thenc可用自动生成回调axios.get(数据地…

onnxruntime无法使用GPU加速 加速失败 解决方法【非常详细】

CreateExecutionProviderInstance CUDA_PATH is set but CUDA wasnt able to be loaded. Please install the correct version of CUDA andcuDNN as mentioned in the GPU requirements page onnxruntime GPU加速onnx 无法使用GPU加速 加速失败 解决方法【非常详细】应该是自目…

jsAPIS-DomEvent

APIs 申明变量const优先 对于变量申明,常见的申明方式包括:var、let、conts。由于var老旧,我们避免使用和var进行变量声明。 那么在定义变量时如何判断使用let还是const? 对于常量(后续不会改变)变量,使用const进行申明。对于会发生变化的变量,使用let进行声明。常见情…

泰山派学习14--pinctr、gpio子系统控制设备树LED

1、在泰山派设备树的/根节点上添加zbl_led子节点(路径:Z:\sdk\linux\kernel\arch\arm64\boot\dts\rockchip)打开tspi-rk3566-user-v10-linux.dts设备树源文件在根目录下添加gpioled子节点2、在SDK上编译kernel(./build.sh kernel)执行内核编译:./build.sh kernel内核编译…

JavaScript全解析——本地存储✔(localStorage~sessionStorage~cookie)

●就是浏览器给我们提供的可以让我们在浏览器上保存一些数据●常用的本地存储(localStorage~sessionStorage~cookie)1-localStorage => 特点:-> 长期存储,除非手动删除否则会一直保存在浏览器中 清除缓存或者卸载浏览器也就没有了-> 可以跨页面通讯, 也就是说在一个…

三种交换方式的比较

一、互联网的核心部分 网络核心部分是互联网中最复杂的部分。 网络中的核心部分要向周围网络边缘的大量主机提供连通性,使边缘部分任何一个主机都能够向其他主机通信。 在网络核心部分起特殊作用的是路由器。 路由器是实现分组交换的关键构件,其任务是转发收到的分组,这是网…

gateway 使用细节

spring:cloud:gateway:routes:- id: test_my_provider # 自定义,全局唯一即可uri: http://localhost:8081 # 实际调用的地址predicates:- Path=/test/** # 请求匹配规则- id: test_my_consumeruri: http://localhost:8082predicates:- Path=/feign/**上一篇文章 gateway 快速入…

长链剖分笔记

与轻重链剖分相似. dfs1:高度 \(h\)、\(son\);dfs2:\(top\). 性质 1:到根最多 \(O(\sqrt n)\) 条轻边. (证明:长链长度最坏情况:1, 2, 3...) 性质 2:\(x\) 的 \(k\) 级祖先 \(y\) 所在的长链长度 \(\ge k\).(证明:若非,则 \(y-x\) 是一条更长的链,矛盾.) 树上 \(…

【漏洞分析】DoughFina 攻击事件分析:不做任何参数检查的去杠杆合约

背景介绍 2024 年 7 月 12 日,DoughFina 协议遭受了黑客攻击,造成本次攻击的主要原因是 ConnectorDeleverageParaswap 合约没有对输入参数进行检查,且该合约为 DSA 合约的 owner。攻击者可以构造恶意参数窃取 DSA 合约的资金。 攻击交易 https://app.blocksec.com/explorer/…

SpringCloud启动报错Did you forget to include spring-cloud-starter-loadbalancer?

当我在gateway项目中添加了feign依赖时,报错:   原因:因为在springcloudFeign在Hoxton.M2 RELEASED版本之后就不再使用Ribbon而是使用spring-cloud-loadbalancer,所以不引入spring-cloud-loadbalancer会报错解决办法:引入依赖即可1 <dependency> 2 …

圆方树

一些概念 割点:无向图中,若删除点x及其连边,连通块变多,那么x为割点。 点双连通:若点对x和y,删除任意非x和非y节点后,x和y仍然联通,称x和y点双连通。 点双联通子图:无向图中的一个子图G,G中任意两点都是点双连通的,那么G为原图的一个点双连通子图。 点双联通分量:无…