JS實(shí)現(xiàn)復(fù)制粘貼文字及圖片功能
一. 基于 Clipboard API 復(fù)制文字(推薦)
基本概念
Clipboard API 是一組用于在瀏覽器中操作剪貼板的 JavaScript API,它允許開(kāi)發(fā)者在網(wǎng)頁(yè)上讀取和寫(xiě)入剪貼板內(nèi)容,實(shí)現(xiàn)復(fù)制、剪切和粘貼等功能。Clipboard API 提供了一種在網(wǎng)頁(yè)上讀取和寫(xiě)入剪貼板內(nèi)容的方式,包括文本、圖像和其他類(lèi)型的數(shù)據(jù)。Clipboard API 適用于需要與用戶剪貼板進(jìn)行交互的網(wǎng)頁(yè)應(yīng)用,如實(shí)現(xiàn)一鍵復(fù)制、粘貼功能,或者在用戶復(fù)制特定內(nèi)容時(shí)自動(dòng)添加額外信息等。
https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard_API
主要方法
Clipboard API 提供了幾個(gè)關(guān)鍵的方法來(lái)實(shí)現(xiàn)剪貼板的讀寫(xiě)操作:
- navigator.clipboard.writeText(text):將給定的文本復(fù)制到剪貼板。這是一個(gè)異步方法,會(huì)返回一個(gè) Promise 對(duì)象,成功時(shí) Promise 會(huì)被解析,失敗時(shí)會(huì)被拒絕。
- navigator.clipboard.readText():從剪貼板讀取文本內(nèi)容。這也是一個(gè)異步方法,返回一個(gè) Promise 對(duì)象,解析后提供剪貼板中的文本內(nèi)容。
- navigator.clipboard.write(data):寫(xiě)入更復(fù)雜的數(shù)據(jù)類(lèi)型到剪貼板,如文件、圖像等。data 參數(shù)是一個(gè)包含 ClipboardItem 對(duì)象的數(shù)組,每個(gè) ClipboardItem 對(duì)象代表剪貼板中的一項(xiàng)數(shù)據(jù)。這也是一個(gè)異步方法,返回一個(gè) Promise 對(duì)象。
- navigator.clipboard.read():從剪貼板讀取更復(fù)雜的數(shù)據(jù)類(lèi)型,如文件、圖像等。這個(gè)方法會(huì)返回一個(gè) Promise 對(duì)象,解析后提供一個(gè)包含 ClipboardItem 對(duì)象的數(shù)組。
使用限制
- 用戶授權(quán):由于安全和隱私的考慮,瀏覽器在使用 Clipboard API 時(shí)通常需要用戶授權(quán)。例如,在嘗試從剪貼板讀取或?qū)懭霐?shù)據(jù)時(shí),瀏覽器可能會(huì)要求用戶明確允許。
- 安全上下文:Clipboard API 只能在安全的環(huán)境中操作剪貼板,如 HTTPS 頁(yè)面、localhost本機(jī)下。
- 瀏覽器兼容性:雖然大多數(shù)現(xiàn)代瀏覽器都支持 Clipboard API,但仍有部分舊版瀏覽器可能不支持。因此,在使用時(shí)需要考慮瀏覽器的兼容性。
實(shí)際應(yīng)用示例
<template> <el-button type="primary" @click="handleCopy">復(fù)制文本</el-button> <div>{{ message }}</div> </template> <script setup> import { ref } from 'vue' import { ElMessage } from 'element-plus' const message = ref('復(fù)制的內(nèi)容') const handleCopy = () => { navigator.clipboard .writeText(message.value) .then(() => { ElMessage({ message: '復(fù)制成功', type: 'success', }) }) .catch((err) => { console.error('復(fù)制失敗:', err) ElMessage({ message: '復(fù)制失敗', type: 'error', }) }) } </script>
二、基于 document.execCommand('copy')
document.execCommand('copy')
是一個(gè)在網(wǎng)頁(yè)上執(zhí)行復(fù)制操作的舊式API,屬于 Web API 的一部分,用于在不需要用戶交互(如點(diǎn)擊或按鍵)的情況下,通過(guò)腳本復(fù)制文本到剪貼板。然而,這個(gè)API在現(xiàn)代Web開(kāi)發(fā)中已經(jīng)被視為過(guò)時(shí)(deprecated),并在許多現(xiàn)代瀏覽器中受到限制或不再支持,尤其是在沒(méi)有用戶明確交互的情況下。
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
缺陷
- 只能操作input, textarea或具有contenteditable屬性的元素
execCommand
是同步操作,如果復(fù)制/粘貼大量數(shù)據(jù),可能會(huì)導(dǎo)致頁(yè)面出現(xiàn)卡頓現(xiàn)象,影響用戶體驗(yàn)。- 它只能將選中的內(nèi)容復(fù)制到剪貼板,無(wú)法向剪貼板任意寫(xiě)入內(nèi)容
- 有些瀏覽器還會(huì)跳出提示框,要求用戶許可,這時(shí)在用戶做出選擇前,頁(yè)面會(huì)失去響應(yīng)。
實(shí)際應(yīng)用示例
<template> <el-button type="primary" @click="handleCopy2">復(fù)制文本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('復(fù)制的內(nèi)容') const handleCopy2 = () => { // 動(dòng)態(tài)創(chuàng)建 textarea 標(biāo)簽 const textarea = document.createElement('textarea') // 將該 textarea 設(shè)為 readonly 防止 iOS 下自動(dòng)喚起鍵盤(pán),同時(shí)將 textarea 移出可視區(qū)域 textarea.readOnly = 'readonly' textarea.style.position = 'absolute' textarea.style.left = '-9999px' textarea.style.opacity = '0' // 將要 copy 的值賦給 textarea 標(biāo)簽的 value 屬性 textarea.value = message.value // 將 textarea 插入到 body 中 document.body.appendChild(textarea) // 選中值并復(fù)制 textarea.select() const result = document.execCommand('Copy') if (result) { ElMessage({ message: '復(fù)制成功', type: 'success', }) } document.body.removeChild(textarea) } </script>
說(shuō)明
clipboard.js
底層也是基于 document.execCommand
去實(shí)現(xiàn)的
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; };
三、復(fù)制圖片功能
<template> <el-button type="primary" @click="handleCopyImage">復(fù)制圖片</el-button> <div>{{ message }}</div> </template> <script setup> import { ref } from 'vue' import { ElMessage } from 'element-plus' const message = ref('復(fù)制的內(nèi)容') const handleCopyImage = async () => { //具體看下面的封裝 await copyImage('https://cn.vitejs.dev/logo-with-shadow.png') ElMessage({ message: '復(fù)制成功', type: 'success', }) } </script>
四、封裝
/** * 圖片轉(zhuǎn)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) } }) } /** * 轉(zhuǎn)換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, } } } /** * 復(fù)制文字 * @param {string} text 要復(fù)制的文本 * @returns {boolean} true/false */ export const copyText = async (text) => { if (navigator && navigator.clipboard) { await navigator.clipboard.writeText(text) return true } // 動(dòng)態(tài)創(chuàng)建 textarea 標(biāo)簽 const textarea = document.createElement('textarea') // 將該 textarea 設(shè)為 readonly 防止 iOS 下自動(dòng)喚起鍵盤(pán),同時(shí)將 textarea 移出可視區(qū)域 textarea.readOnly = 'readonly' textarea.style.position = 'absolute' textarea.style.left = '-9999px' textarea.style.opacity = '0' // 將要 copy 的值賦給 textarea 標(biāo)簽的 value 屬性 textarea.value = text // 將 textarea 插入到 body 中 document.body.appendChild(textarea) // 選中值并復(fù)制 textarea.select() const result = document.execCommand('Copy') document.body.removeChild(textarea) return result } /** * 復(fù)制圖片 * @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轉(zhuǎn)為Blob類(lèi)型 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 })]) }
到此這篇關(guān)于JS實(shí)現(xiàn)復(fù)制粘貼文字以及圖片的文章就介紹到這了,更多相關(guān)js復(fù)制粘貼文字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- js實(shí)現(xiàn)復(fù)制粘貼的兩種方法
- 基于js實(shí)現(xiàn)復(fù)制內(nèi)容到操作系統(tǒng)粘貼板過(guò)程解析
- JS插件clipboard.js實(shí)現(xiàn)一鍵復(fù)制粘貼功能
- 20行JS代碼實(shí)現(xiàn)粘貼板復(fù)制功能
- JS復(fù)制對(duì)應(yīng)id的內(nèi)容到粘貼板(Ctrl+C效果)
- JavaScript禁止復(fù)制與粘貼的實(shí)現(xiàn)代碼
- JS基于clipBoard.js插件實(shí)現(xiàn)剪切、復(fù)制、粘貼
- js實(shí)現(xiàn)點(diǎn)擊圖片將圖片地址復(fù)制到粘貼板的方法
相關(guān)文章
JS中showModalDialog關(guān)閉子窗口刷新主窗口用法詳解
這篇文章主要介紹了JS中showModalDialog關(guān)閉子窗口刷新主窗口用法,結(jié)合具體實(shí)例形式較為詳細(xì)的分析了showModalDialog常見(jiàn)用法與相關(guān)使用技巧,需要的朋友可以參考下2017-03-03javascript 制作坦克大戰(zhàn)游戲初步 圖片與代碼
javascript 制作坦克大戰(zhàn)游戲初步 圖片與代碼...2007-11-11詳解webpack-dev-server使用http-proxy解決跨域問(wèn)題
這篇文章主要介紹了詳解webpack-dev-server使用http-proxy解決跨域問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01uniapp實(shí)現(xiàn)app自動(dòng)更新詳細(xì)步驟
這篇文章主要給大家介紹了關(guān)于uniapp實(shí)現(xiàn)app自動(dòng)更新的詳細(xì)步驟,文中給出了詳細(xì)的代碼示例以及圖文教程,對(duì)大家學(xué)習(xí)或者使用uniapp具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-08-08Javascript實(shí)現(xiàn)的常用算法(如冒泡、快速、鴿巢、奇偶等)
這篇文章主要介紹了Javascript實(shí)現(xiàn)的常用算法,如冒泡、快速、鴿巢、選擇、木桶、奇偶等,需要的朋友可以參考下2014-04-04JavaScript實(shí)現(xiàn)拖動(dòng)模態(tài)框
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)拖動(dòng)模態(tài)框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07JavaScript實(shí)現(xiàn)中文數(shù)字轉(zhuǎn)為阿拉伯?dāng)?shù)字的方法
在JavaScript編程中,實(shí)現(xiàn)阿拉伯?dāng)?shù)字和中文數(shù)字之間的互相轉(zhuǎn)換是一個(gè)常見(jiàn)的需求,這涉及到字符串處理和數(shù)值計(jì)算,本文將詳細(xì)介紹如何利用JavaScript實(shí)現(xiàn)這一功能,需要的朋友可以參考下2025-03-03electron的webview和內(nèi)嵌網(wǎng)頁(yè)通信的方法
在 Electron 的世界里,webview 標(biāo)簽相當(dāng)于一個(gè)小盒子,里面可以裝一個(gè)完整的網(wǎng)頁(yè),就像一個(gè)迷你瀏覽器,這篇文章主要介紹了electron的webview和內(nèi)嵌網(wǎng)頁(yè)如何通信,需要的朋友可以參考下2024-04-04配置eslint規(guī)范項(xiàng)目代碼風(fēng)格
這篇文章主要介紹了配置eslint規(guī)范項(xiàng)目代碼風(fēng)格,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03Three.js實(shí)現(xiàn)3D乒乓球小游戲(物理效果)
本文將使用React Three Fiber 和 Cannon.js 來(lái)實(shí)現(xiàn)一個(gè)具有物理特性的乒乓球小游戲,使用 React Three Fiber 搭建基礎(chǔ)三維場(chǎng)景、如何使用新技術(shù)棧給場(chǎng)景中對(duì)象的添加物理特性等,最后利用上述知識(shí)點(diǎn),將開(kāi)發(fā)一個(gè)簡(jiǎn)單的乒乓球小游戲,需要的朋友可以參考下2023-03-03