You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
5.4 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// main.js
// 当整个页面的HTML内容加载完成后执行此函数
document.addEventListener('DOMContentLoaded', () => {
// 获取页面上的关键元素
const textInput = document.getElementById('text-input');
const generateBtn = document.getElementById('generate-btn');
const qrcodeContainer = document.getElementById('qrcode-container');
// 为“生成二维码”按钮添加点击事件监听器
generateBtn.addEventListener('click', () => {
// 获取输入框中的文本,并用 trim() 清除前后的空白字符
const text = textInput.value.trim();
// 在生成新的二维码之前,清空之前可能存在的旧二维码
qrcodeContainer.innerHTML = '';
// 如果文本为空,则不执行任何操作
if (!text) {
console.log('输入内容为空,已中止生成。');
return;
}
// --- 智能分割逻辑 ---
// 我们使用一个固定的字节数上限。这是二维码国标GB/T 18284-2000规定的
// 在版本40、纠错等级H最高的情况下最大可容纳的字节数。
const MAX_BYTES_PER_QR = 1273;
const textEncoder = new TextEncoder(); // 用于计算字符串的UTF-8字节长度
const chunks = [];
let currentPos = 0;
while (currentPos < text.length) {
// 使用二分查找来高效地找到当前位置后,能容纳在单个二维码中的最长子字符串
let low = currentPos;
let high = text.length;
let bestEnd = currentPos;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
// mid不能停在原点否则会死循环
if (mid === currentPos) {
low = mid + 1;
continue;
}
const substring = text.substring(currentPos, mid);
const byteLength = textEncoder.encode(substring).length;
if (byteLength <= MAX_BYTES_PER_QR) {
// 如果当前子字符串的字节长度在限制内,说明它是一个有效的块
// 我们记录下这个有效的终点,并尝试寻找更长的块
bestEnd = mid;
low = mid + 1;
} else {
// 如果超出了字节限制,则需要缩短子字符串的长度
high = mid - 1;
}
}
// 处理极端情况:如果单个字符的字节数就超过了上限,我们也只能把它单独作为一个块
if (bestEnd === currentPos && currentPos < text.length) {
bestEnd = currentPos + 1;
}
// 将找到的最佳块添加到数组中
chunks.push(text.substring(currentPos, bestEnd));
// 从新的位置继续寻找下一个块
currentPos = bestEnd;
}
const totalChunks = chunks.length;
console.log(`总字符数: ${text.length},通过智能分割,将生成 ${totalChunks} 个二维码。`);
// --- 循环生成二维码 ---
chunks.forEach((chunk, i) => {
// --- 创建包裹单个二维码及其标签的容器 ---
const itemDiv = document.createElement('div');
itemDiv.className = 'qrcode-item';
// --- 创建并添加序号标签 ---
const label = document.createElement('p');
label.className = 'qrcode-label';
label.textContent = totalChunks > 1 ? `二维码 ${i + 1}/${totalChunks}` : '二维码';
itemDiv.appendChild(label);
// --- 创建用于绘制二维码的 <canvas> 元素 ---
const canvas = document.createElement('canvas');
itemDiv.appendChild(canvas);
qrcodeContainer.appendChild(itemDiv);
// --- 使用 QRCode.toCanvas 方法将二维码绘制到指定的 canvas 上 ---
QRCode.toCanvas(
canvas,
chunk,
{
margin: 2, // 二维码边距
color: {
dark: '#000000', // 二维码深色部分
light: '#ffffff', // 二维码浅色部分
},
errorCorrectionLevel: 'H', // 纠错级别: 'L', 'M', 'Q', 'H'
},
function (error) {
if (error) {
console.error(`为第 ${i + 1} 块内容生成二维码时出错:`, error);
// 如果生成失败,在 canvas 上显示错误信息
const ctx = canvas.getContext('2d');
if (ctx) {
// 设置一个基础尺寸以防canvas没有宽高
canvas.width = 400;
canvas.height = 400;
ctx.font = '20px Arial';
ctx.fillStyle = 'red';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('二维码生成失败', canvas.width / 2, canvas.height / 2);
}
} else {
console.log(`已成功为第 ${i + 1} 块内容生成二维码。`);
}
}
);
});
});
});