JS實現(xiàn)復制粘貼文字及圖片功能
一. 基于 Clipboard API 復制文字(推薦)
基本概念
Clipboard API 是一組用于在瀏覽器中操作剪貼板的 JavaScript API,它允許開發(fā)者在網頁上讀取和寫入剪貼板內容,實現(xiàn)復制、剪切和粘貼等功能。Clipboard API 提供了一種在網頁上讀取和寫入剪貼板內容的方式,包括文本、圖像和其他類型的數據。Clipboard API 適用于需要與用戶剪貼板進行交互的網頁應用,如實現(xiàn)一鍵復制、粘貼功能,或者在用戶復制特定內容時自動添加額外信息等。
https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard_API
主要方法
Clipboard API 提供了幾個關鍵的方法來實現(xiàn)剪貼板的讀寫操作:
- 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 只能在安全的環(huán)境中操作剪貼板,如 HTTPS 頁面、localhost本機下。
- 瀏覽器兼容性:雖然大多數現(xiàn)代瀏覽器都支持 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') 是一個在網頁上執(zhí)行復制操作的舊式API,屬于 Web API 的一部分,用于在不需要用戶交互(如點擊或按鍵)的情況下,通過腳本復制文本到剪貼板。然而,這個API在現(xiàn)代Web開發(fā)中已經被視為過時(deprecated),并在許多現(xiàn)代瀏覽器中受到限制或不再支持,尤其是在沒有用戶明確交互的情況下。
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
缺陷
- 只能操作input, textarea或具有contenteditable屬性的元素
execCommand是同步操作,如果復制/粘貼大量數據,可能會導致頁面出現(xiàn)卡頓現(xiàn)象,影響用戶體驗。- 它只能將選中的內容復制到剪貼板,無法向剪貼板任意寫入內容
- 有些瀏覽器還會跳出提示框,要求用戶許可,這時在用戶做出選擇前,頁面會失去響應。
實際應用示例
<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 = () => {
// 動態(tài)創(chuàng)建 textarea 標簽
const textarea = document.createElement('textarea')
// 將該 textarea 設為 readonly 防止 iOS 下自動喚起鍵盤,同時將 textarea 移出可視區(qū)域
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去實現(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;
};三、復制圖片功能
<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
}
// 動態(tài)創(chuàng)建 textarea 標簽
const textarea = document.createElement('textarea')
// 將該 textarea 設為 readonly 防止 iOS 下自動喚起鍵盤,同時將 textarea 移出可視區(qū)域
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 })])
}到此這篇關于JS實現(xiàn)復制粘貼文字以及圖片的文章就介紹到這了,更多相關js復制粘貼文字內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
深入聊聊Array的sort方法的使用技巧.詳細點評protype.js中的sortBy方法
深入聊聊Array的sort方法的使用技巧.詳細點評protype.js中的sortBy方法...2007-04-04
JavaScript使用map()方法遍歷數組并返回新數組的代碼示例
在 JavaScript 中,數組是最常用的數據結構之一,遍歷數組以執(zhí)行某種操作是我們開發(fā)中的常見任務,map() 方法是數組的一個內置方法,本文將詳細介紹如何使用 map() 方法來遍歷數組并返回一個新的數組,需要的朋友可以參考下2025-06-06

