image.png

这是一个基于 HTML、Tailwind CSS 和 JavaScript 构建的纯前端二维码生成与解析工具,无需后端部署,打开即用。它主要具备以下特点:

  • 核心功能:支持将文本或网址快速生成二维码,并可下载为高清图片;同时支持上传二维码图片,智能解析其中的内容。

  • 技术亮点:采用 Tailwind CSS 实现响应式布局与玻璃拟态 UI,结合 AOS 和 GSAP 增强页面交互动效,通过调用免费 API 完成二维码的编解码。

  • 适配体验:完美兼容移动端和桌面端,加载状态、错误提示等细节处理到位,交互体验流畅自然。

如果你想要其他风格(如更简洁、更营销化),也可以告诉我,我会帮你进一步调整。

直接展出代码:

(可以复制代码在:代码在线运行工具 - 墨桅博客   看效果)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>二维码生成与解析工具 - 墨桅博客</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3b82f6',
                        secondary: '#64748b',
                        success: '#10b981',
                        warning: '#f59e0b',
                        danger: '#ef4444',
                        dark: '#1e293b',
                        light: '#f8fafc'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif']
                    },
                    boxShadow: {
                        'card': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
                        'hover': '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)'
                    }
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .glass-effect {
                background: rgba(255, 255, 255, 0.8);
                backdrop-filter: blur(10px);
                -webkit-backdrop-filter: blur(10px);
                border: 1px solid rgba(255, 255, 255, 0.2);
            }
            .gradient-bg {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }
            .card-hover {
                transition: all 0.3s ease;
            }
            .card-hover:hover {
                transform: translateY(-5px);
            }
            .btn-primary {
                background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
                transition: all 0.3s ease;
            }
            .btn-primary:hover {
                transform: translateY(-2px);
                box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
            }
            .btn-secondary {
                background: linear-gradient(135deg, #64748b 0%, #475569 100%);
                transition: all 0.3s ease;
            }
            .btn-secondary:hover {
                transform: translateY(-2px);
                box-shadow: 0 10px 20px rgba(100, 116, 139, 0.3);
            }
        }
    </style>
    <script>
        // 墨桅博客 https://www.jetmast.com
    </script>
</head>
<body class="bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 min-h-screen">
    <div class="container mx-auto px-4 py-12">
        <header class="text-center mb-12">
            <div class="inline-block p-2 bg-white rounded-full shadow-lg mb-4" data-aos="fade-down">
                <i class="fa fa-qrcode text-5xl text-primary"></i>
            </div>
            <h1 class="text-5xl font-bold text-dark mb-3" data-aos="fade-up" data-aos-delay="100">二维码生成与解析工具</h1>
            <p class="text-xl text-gray-600 max-w-2xl mx-auto" data-aos="fade-up" data-aos-delay="200">
                快速生成和解析二维码,支持自定义内容,提供高质量图片下载
            </p>
        </header>

        <main class="max-w-7xl mx-auto">
            <div class="flex flex-col lg:flex-row gap-8">
                <div class="glass-effect rounded-2xl shadow-card p-8 card-hover flex-1" data-aos="fade-right" data-aos-delay="100">
                    <div class="flex items-center mb-6">
                        <div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mr-4">
                            <i class="fa fa-qrcode text-2xl text-primary"></i>
                        </div>
                        <h2 class="text-2xl font-bold text-dark">生成二维码</h2>
                    </div>

                    <div class="space-y-6">
                        <div>
                            <label class="block text-lg font-medium text-gray-700 mb-3">输入内容</label>
                            <textarea id="qr-content" rows="4" class="w-full px-4 py-3 text-lg border border-gray-300 rounded-xl focus:outline-none focus:ring-3 focus:ring-primary/50 transition-all" placeholder="请输入要生成二维码的文本或网址..."></textarea>
                        </div>

                        <button onclick="generateQRCode()" class="w-full btn-primary text-white font-semibold py-4 px-6 rounded-xl text-lg shadow-lg">
                            <i class="fa fa-qrcode mr-3"></i>生成二维码
                        </button>

                        <div id="result-container" class="hidden">
                            <div class="bg-white rounded-xl p-6 text-center shadow-lg border border-gray-100">
                                <div class="inline-block p-4 bg-gray-50 rounded-lg mb-6">
                                    <img id="qr-image" src="" alt="二维码" class="mx-auto w-40 h-40 object-contain">
                                </div>
                                <div class="flex justify-center space-x-4">
                                    <button onclick="downloadQRCode()" class="bg-success hover:bg-green-600 text-white px-6 py-3 rounded-lg text-base font-medium transition-all hover:shadow-lg">
                                        <i class="fa fa-download mr-2"></i>下载二维码
                                    </button>
                                </div>
                            </div>
                        </div>

                        <div id="loading-container" class="hidden">
                            <div class="text-center py-12">
                                <div class="inline-block">
                                    <i class="fa fa-spinner fa-spin text-4xl text-primary mb-4"></i>
                                </div>
                                <p class="text-lg text-gray-600 font-medium">正在生成二维码...</p>
                            </div>
                        </div>

                        <div id="error-container" class="hidden">
                            <div class="bg-red-50 border border-red-200 rounded-xl p-6 shadow-md">
                                <div class="flex items-start">
                                    <div class="bg-red-100 rounded-full p-3 mr-4">
                                        <i class="fa fa-exclamation-circle text-red-500 text-xl"></i>
                                    </div>
                                    <div>
                                        <h3 class="text-lg font-semibold text-red-800 mb-2">生成失败</h3>
                                        <p id="error-message" class="text-base text-red-700"></p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="glass-effect rounded-2xl shadow-card p-8 card-hover flex-1" data-aos="fade-left" data-aos-delay="200">
                    <div class="flex items-center mb-6">
                        <div class="w-12 h-12 bg-gray-100 rounded-lg flex items-center justify-center mr-4">
                            <i class="fa fa-search text-2xl text-secondary"></i>
                        </div>
                        <h2 class="text-2xl font-bold text-dark">解析二维码</h2>
                    </div>

                    <div class="space-y-6">
                        <div>
                            <label class="block text-lg font-medium text-gray-700 mb-3">上传二维码图片</label>
                            <div class="relative">
                                <input type="file" id="qr-file" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer">
                                <div class="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center transition-all hover:border-secondary">
                                    <i class="fa fa-cloud-upload text-4xl text-gray-400 mb-4"></i>
                                    <p class="text-gray-600 mb-2">点击或拖拽文件到此处上传</p>
                                    <p class="text-sm text-gray-500">支持 JPG、PNG、WEBP 格式</p>
                                </div>
                            </div>
                        </div>

                        <button onclick="decodeQRCode()" class="w-full btn-secondary text-white font-semibold py-4 px-6 rounded-xl text-lg shadow-lg">
                            <i class="fa fa-search mr-3"></i>解析二维码
                        </button>

                        <div id="decode-result" class="hidden">
                            <div class="bg-white rounded-xl p-6 shadow-lg border border-gray-100">
                                <div class="flex items-center mb-4">
                                    <div class="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center mr-3">
                                        <i class="fa fa-check text-success"></i>
                                    </div>
                                    <h3 class="text-xl font-semibold text-gray-800">解析结果</h3>
                                </div>
                                <div id="decode-content" class="text-base font-mono bg-gray-50 p-4 border border-gray-200 rounded-lg break-all max-h-40 overflow-y-auto"></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </main>

        <footer class="text-center text-gray-600 mt-16">
            <div class="glass-effect inline-block px-8 py-4 rounded-full shadow-md">
                <p id="copyright" class="text-lg font-medium"></p>
            </div>
        </footer>
    </div>

    <script>
        function initCopyright() {
            const owner = '墨桅博客';
            const year = new Date().getFullYear();
            document.getElementById('copyright').textContent = `© ${year} ${owner} 保留所有权利`;
        }

        function generateQRCode() {
            const content = document.getElementById('qr-content').value.trim();

            if (!content) {
                showError('请输入要生成二维码的内容');
                return;
            }

            document.getElementById('result-container').style.display = 'none';
            document.getElementById('error-container').style.display = 'none';
            document.getElementById('loading-container').style.display = 'block';

            const apiUrl = `https://v2.xxapi.cn/api/qrcode?text=${encodeURIComponent(content)}&return=json`;

            console.log('调用API:', apiUrl);

            fetch(apiUrl)
                .then(response => {
                    if (!response.ok) {
                        throw new Error('API请求失败: ' + response.status);
                    }
                    return response.json();
                })
                .then(data => {
                    console.log('API响应:', data);

                    document.getElementById('loading-container').style.display = 'none';

                    if (data.code === '200' || data.code === 200) {
                        const qrImage = document.getElementById('qr-image');
                        qrImage.src = data.data;
                        qrImage.style.width = '200px';
                        qrImage.style.height = '200px';

                        document.getElementById('result-container').style.display = 'block';
                    } else {
                        showError(data.msg || '生成失败,请重试');
                    }
                })
                .catch(error => {
                    console.error('生成失败:', error);
                    document.getElementById('loading-container').style.display = 'none';
                    showError('生成失败: ' + error.message);
                });
        }

        function downloadQRCode() {
            const qrImage = document.getElementById('qr-image');
            if (!qrImage.src) return;

            const link = document.createElement('a');
            link.href = qrImage.src;
            link.download = '二维码.png';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }

        // 使用 jsQR 库在客户端本地解析二维码,不再依赖外部API
        function decodeQRCode() {
            const fileInput = document.getElementById('qr-file');
            const file = fileInput.files[0];

            if (!file) {
                alert('请选择要解析的二维码图片');
                return;
            }

            const reader = new FileReader();
            reader.onload = function(e) {
                const img = new Image();
                img.onload = function() {
                    // 创建 canvas 绘制图片
                    const canvas = document.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0, img.width, img.height);

                    // 获取图像数据
                    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

                    // 使用 jsQR 解码
                    const code = jsQR(imageData.data, canvas.width, canvas.height);

                    if (code) {
                        document.getElementById('decode-content').textContent = code.data;
                        document.getElementById('decode-result').style.display = 'block';
                    } else {
                        alert('未能识别二维码,请确保图片包含清晰的二维码');
                    }
                };
                img.onerror = function() {
                    alert('图片加载失败,请检查文件格式');
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
        }

        function showError(message) {
            document.getElementById('loading-container').style.display = 'none';
            document.getElementById('error-message').textContent = message;
            document.getElementById('error-container').style.display = 'block';
        }

        document.addEventListener('DOMContentLoaded', function() {
            initCopyright();
            AOS.init({
                duration: 800,
                easing: 'ease-in-out',
                once: true
            });
            console.log('二维码工具已初始化');

            const fileInput = document.getElementById('qr-file');
            fileInput.addEventListener('change', function(e) {
                const file = e.target.files[0];
                if (file) {
                    const uploadArea = this.parentElement.querySelector('.border');
                    uploadArea.classList.add('border-success');
                    uploadArea.classList.remove('border-gray-300', 'hover:border-secondary');
                }
            });
        });
    </script>
</body>
</html>