Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Tạo tính năng Copy to Clipboard trên trang web với JavaScript

Copy to Clipboard - Copy văn bản vào clipboard

Có 2 cách chính: cách cũ dùng document.execCommand('copy') (deprecated nhưng vẫn dùng được) và cách hiện đại dùng Clipboard API (navigator.clipboard.writeText()).

Cách hiện đại: Clipboard API (Khuyến nghị)

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Copy to Clipboard</title>
    <style>
        body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 20px; }
        .result { font-size: 18px; font-weight: 500; color: rebeccapurple; margin-top: 15px; }
        input, button { padding: 10px; font-size: 16px; }
        .success { color: green; }
        .error { color: red; }
    </style>
</head>
<body>
    <h1>Copy to Clipboard (Clipboard API)</h1>
    <input type="text" id="textInput" placeholder="Nhập văn bản để copy" style="width: 300px;" />
    <button id="btnCopy">COPY</button>
    <br><br>
    <input type="text" id="pasteArea" placeholder="Dán vào đây để kiểm tra" style="width: 300px;" />
    <div class="result" id="status"></div>

    <script>
        const textInput = document.getElementById('textInput');
        const pasteArea = document.getElementById('pasteArea');
        const btnCopy = document.getElementById('btnCopy');
        const status = document.getElementById('status');

        btnCopy.addEventListener('click', async () => {
            const text = textInput.value;
            if (!text) {
                status.textContent = 'Vui lòng nhập văn bản!';
                status.className = 'result error';
                return;
            }

            try {
                // Clipboard API - yêu cầu HTTPS hoặc localhost
                await navigator.clipboard.writeText(text);
                status.textContent = '✓ Đã copy vào clipboard!';
                status.className = 'result success';
            } catch (err) {
                status.textContent = '✗ Lỗi: ' + err.message;
                status.className = 'result error';
            }
        });

        // Cho phép dán (paste) để test
        pasteArea.addEventListener('paste', (e) => {
            status.textContent = 'Đã dán: ' + e.clipboardData.getData('text');
            status.className = 'result';
        });
    </script>
</body>
</html>

Cách cũ: execCommand (Deprecated)

function copyOldWay(text) {
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed'; // Tránh scroll
    document.body.appendChild(textarea);
    textarea.select();
    try {
        const successful = document.execCommand('copy');
        console.log(successful ? 'Copied!' : 'Failed');
    } catch (err) {
        console.error('Copy failed:', err);
    }
    document.body.removeChild(textarea);
}

So sánh

Đặc điểm Clipboard API execCommand
Trạng tháiChuẩn hiện đạiDeprecated
Async/Promise✓ (async/await)✗ (Sync)
Yêu cầu HTTPSCó (trừ localhost)Không
Quyền truy cậpCần permission (user gesture)Cần user gesture
Hỗ trợChrome 66+, FF 63+, Safari 13.1+, Edge 79+Mọi trình duyệt cũ

Xử lý quyền (Permissions)

// Kiểm tra quyền clipboard
const permission = await navigator.permissions.query({ name: 'clipboard-write' });
console.log(permission.state); // 'granted', 'denied', 'prompt'

// Lắng nghe thay đổi quyền
permission.onchange = () => {
    console.log('Permission changed to:', permission.state);
};

Copy nội dung phức tạp (HTML, Image)

// Copy HTML
async function copyHTML(html) {
    const blob = new Blob([html], { type: 'text/html' });
    const data = [new ClipboardItem({ 'text/html': blob })];
    await navigator.clipboard.write(data);
}

// Copy Image
async function copyImage(imgElement) {
    const canvas = document.createElement('canvas');
    canvas.width = imgElement.naturalWidth;
    canvas.height = imgElement.naturalHeight;
    canvas.getContext('2d').drawImage(imgElement, 0, 0);
    const blob = await new Promise(r => canvas.toBlob(r));
    await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);
}

Fallback cho trình duyệt cũ

async function copyToClipboard(text) {
    if (navigator.clipboard && window.isSecureContext) {
        // Modern API
        return navigator.clipboard.writeText(text);
    } else {
        // Fallback execCommand
        return new Promise((resolve, reject) => {
            const textarea = document.createElement('textarea');
            textarea.value = text;
            textarea.style.position = 'fixed';
            document.body.appendChild(textarea);
            textarea.select();
            try {
                resolve(document.execCommand('copy'));
            } catch (err) {
                reject(err);
            } finally {
                document.body.removeChild(textarea);
            }
        });
    }
}