jQuery实现HTML代码复制功能

我将创建一个带有复制功能的代码块界面,实现点击复制按钮时复制代码内容,并显示成功状态。

思路分析

  1. 使用jQuery实现复制功能
  2. 添加视觉反馈:复制成功后显示”已复制”状态
  3. 1秒后自动恢复初始状态
  4. 确保代码在各种情况下都能正常复制

最终实现代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>代码复制功能</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        :root {
            --bs-dark: #212529;
        }

        pre.wp-block-code {
            position: relative;
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 0.375rem;
            padding: 1rem;
            margin: 1rem 0;
            overflow-x: auto;
        }

        pre.wp-block-code code {
            display: block;
            font-family: 'Courier New', monospace;
            font-size: 0.875rem;
            color: #212529;
            line-height: 1.5;
        }

        pre.wp-block-code .copy {
            display: table;
            position: absolute;
            right: 1rem;
            top: 1rem;
            z-index: 1;
            background-color: rgba(255, 255, 255, 0.8);
            border-radius: 0.25rem;
            padding: 0.25rem;
        }

        pre.wp-block-code .copy .inc-svg {
            display: block;
            width: 1.5rem;
            cursor: pointer;
            opacity: 0.8;
            transition: opacity 0.2s;
        }

        pre.wp-block-code .copy .inc-svg:hover {
            opacity: 1;
        }

        pre.wp-block-code .copy .copied {
            display: none;
        }

        pre.wp-block-code .copy .inc-svg svg {
            display: block;
            width: 100% !important;
            height: auto !important;
            fill: var(--bs-dark) !important;
        }

        .code-container {
            max-width: 800px;
            margin: 2rem auto;
            padding: 0 1rem;
        }

        h1 {
            text-align: center;
            margin-bottom: 2rem;
            color: #333;
        }

        .description {
            background-color: #e9ecef;
            padding: 1rem;
            border-radius: 0.375rem;
            margin-bottom: 1.5rem;
        }
    </style>
</head>
<body>
    <div class="code-container">
        <h1>代码复制功能演示</h1>

        <div class="description">
            <p>点击代码块右上角的复制按钮,可以复制代码内容。复制成功后按钮会短暂显示"已复制"状态,然后自动恢复。</p>
        </div>

        <pre class="wp-block-code">
            <code>// 示例代码:计算斐波那契数列
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// 打印前10个斐波那契数
for (let i = 0; i < 10; i++) {
    console.log(`fibonacci(${i}) = ${fibonacci(i)}`);
}</code>
            <div class="copy">
                <span class="nocopy inc-svg">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard2-check" viewBox="0 0 16 16">
                        <path d="M9.5 0a.5.5 0 0 1 .5.5.5.5 0 0 0 .5.5.5.5 0 0 1 .5.5V2a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 2v-.5a.5.5 0 0 1 .5-.5.5.5 0 0 0 .5-.5.5.5 0 0 1 .5-.5z"></path>
                        <path d="M3 2.5a.5.5 0 0 1 .5-.5H4a.5.5 0 0 0 0-1h-.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-12A1.5 1.5 0 0 0 12.5 1H12a.5.5 0 0 0 0 1h.5a.5.5 0 0 1 .5.5v12a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5z"></path>
                        <path d="M10.854 7.854a.5.5 0 0 0-.708-.708L7.5 9.793 6.354 8.646a.5.5 0 1 0-.708.708l1.5 1.5a.5.5 0 0 0 .708 0z"></path>
                    </svg>
                </span>
                <span class="copied inc-svg">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard2-check-fill" viewBox="0 0 16 16">
                        <path d="M10 .5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5.5.5 0 0 1-.5.5.5.5 0 0 0-.5.5V2a.5.5 0 0 0 .5.5h5A.5.5 0 0 0 11 2v-.5a.5.5 0 0 0-.5-.5.5.5 0 0 1-.5-.5"></path>
                        <path d="M4.085 1H3.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-12A1.5 1.5 0 0 0 12.5 1h-.585q.084.236.085.5V2a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 2v-.5q.001-.264.085-.5m6.769 6.854-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708.708"></path>
                    </svg>
                </span>
            </div>
        </pre>

        <pre class="wp-block-code">
            <code>// 另一个示例:数组排序函数
function bubbleSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换元素
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}

// 使用示例
let numbers = [64, 34, 25, 12, 22, 11, 90];
console.log("排序前:", numbers);
console.log("排序后:", bubbleSort(numbers));</code>
            <div class="copy">
                <span class="nocopy inc-svg">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard2-check" viewBox="0 0 16 16">
                        <path d="M9.5 0a.5.5 0 0 1 .5.5.5.5 0 0 0 .5.5.5.5 0 0 1 .5.5V2a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 2v-.5a.5.5 0 0 1 .5-.5.5.5 0 0 0 .5-.5.5.5 0 0 1 .5-.5z"></path>
                        <path d="M3 2.5a.5.5 0 0 1 .5-.5H4a.5.5 0 0 0 0-1h-.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-12A1.5 1.5 0 0 0 12.5 1H12a.5.5 0 0 0 0 1h.5a.5.5 0 0 1 .5.5v12a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5z"></path>
                        <path d="M10.854 7.854a.5.5 0 0 0-.708-.708L7.5 9.793 6.354 8.646a.5.5 0 1 0-.708.708l1.5 1.5a.5.5 0 0 0 .708 0z"></path>
                    </svg>
                </span>
                <span class="copied inc-svg">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard2-check-fill" viewBox="0 0 16 16">
                        <path d="M10 .5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5.5.5 0 0 1-.5.5.5.5 0 0 0-.5.5V2a.5.5 0 0 0 .5.5h5A.5.5 0 0 0 11 2v-.5a.5.5 0 0 0-.5-.5.5.5 0 0 1-.5-.5"></path>
                        <path d="M4.085 1H3.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-12A1.5 1.5 0 0 0 12.5 1h-.585q.084.236.085.5V2a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 2v-.5q.001-.264.085-.5m6.769 6.854-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708.708"></path>
                    </svg>
                </span>
            </div>
        </pre>
    </div>

    <script>
        $(document).ready(function() {
            // 为所有复制按钮绑定点击事件
            $('.copy').on('click', function() {
                // 获取当前代码块中的代码文本
                const codeText = $(this).closest('pre.wp-block-code').find('code').text();

                // 复制文本到剪贴板
                copyToClipboard(codeText);

                // 切换图标状态
                const $nocopy = $(this).find('.nocopy');
                const $copied = $(this).find('.copied');

                // 隐藏nocopy,显示copied
                $nocopy.hide();
                $copied.show();

                // 1秒后恢复状态
                setTimeout(function() {
                    $copied.hide();
                    $nocopy.show();
                }, 1000);
            });

            // 复制文本到剪贴板的函数
            function copyToClipboard(text) {
                // 尝试使用现代剪贴板API
                if (navigator.clipboard && window.isSecureContext) {
                    navigator.clipboard.writeText(text).then(function() {
                        console.log('复制成功!');
                    }).catch(function(err) {
                        console.error('复制失败:', err);
                        fallbackCopy(text);
                    });
                } else {
                    // 使用备用方法
                    fallbackCopy(text);
                }
            }

            // 备用复制方法
            function fallbackCopy(text) {
                const textArea = document.createElement("textarea");
                textArea.value = text;

                // 避免屏幕滚动
                textArea.style.top = "0";
                textArea.style.left = "0";
                textArea.style.position = "fixed";

                document.body.appendChild(textArea);
                textArea.focus();
                textArea.select();

                try {
                    const successful = document.execCommand('copy');
                    if (successful) {
                        console.log('复制成功!');
                    } else {
                        console.error('复制失败');
                    }
                } catch (err) {
                    console.error('复制失败:', err);
                }

                document.body.removeChild(textArea);
            }
        });
    </script>
</body>
</html>

功能说明

  1. 复制功能:点击代码块右上角的复制按钮,可以复制代码内容
  2. 视觉反馈:复制成功后,按钮会短暂显示”已复制”状态
  3. 自动恢复:1秒后按钮自动恢复为初始状态
  4. 兼容性:使用了现代剪贴板API,并有备用方案确保在各种浏览器中都能正常工作

这个实现满足了所有要求,并提供了两个示例代码块来演示功能。复制功能使用了两种方法确保兼容性,并提供了清晰的用户反馈。