JavaScript 中关卡导入导出快捷键为何无法正常工作?
数据小陈
结论
仅凭这段代码无法确定具体故障原因,因为没有提供异常表现或控制台报错。可以先检查两处:btoa() 无法直接编码含中文等非 Latin-1 字符的 JSON 字符串;快捷键监听器则会在焦点位于输入框时触发。还要注意,Base64 只是编码,不具备加密功能。
title 和 author 的值来自 prompt()。如果输入中文等字符,JSON.stringify(data) 会包含这些字符,直接传给 btoa() 可能触发 InvalidCharacterError,导致导出中断。可以查看浏览器控制台是否有这条错误。
用 UTF-8 处理 Base64
先添加 UTF-8 编码和解码函数:
function encodeBase64Utf8(text) {
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
function decodeBase64Utf8(code) {
const binary = atob(code.trim());
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
在 exportLevel() 中,将:
const code = btoa(JSON.stringify(data));
替换为:
const code = encodeBase64Utf8(JSON.stringify(data));
在 loadFromCode() 中,将:
const data = JSON.parse(atob(code));
替换为:
const data = JSON.parse(decodeBase64Utf8(code));
检查导入数据后再更新网格
当前代码会直接读取 data.grid[y][x]。如果粘贴的代码无效、网格行列数与当前 gridSize 不一致,或数据结构不完整,循环中就可能报错。catch 虽然会显示 Invalid save code!,但如果异常发生前已有部分网格更新,画面状态可能不完整。
可以先检查数据结构,通过后再更新网格:
function loadFromCode(code) {
try {
const data = JSON.parse(decodeBase64Utf8(code));
if (!data || !Array.isArray(data.grid) || data.grid.length !== gridSize) {
throw new Error('Invalid grid height');
}
const hasValidRows = data.grid.every(
row => Array.isArray(row) && row.length === gridSize
);
if (!hasValidRows) {
throw new Error('Invalid grid width');
}
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
grid[y][x].type = data.grid[y][x];
}
}
levelTitle = data.title || 'Untitled Level';
levelAuthor = data.author || 'Unknown';
player = null;
gameStarted = false;
renderGrid();
updateLevelMeta();
alert(`Level loaded!\n${levelTitle} By: ${levelAuthor}`);
} catch (error) {
console.error('Unable to load level:', error);
alert('Invalid save code!');
}
}
这里假设每个关卡的尺寸都是 gridSize × gridSize。如果游戏支持不同尺寸的关卡,需要根据实际数据格式调整校验条件。
避免在输入文字时触发快捷键
当前的 keydown 监听器在页面任何位置都会生效。用户输入标题、作者名或其他表单内容时,也可能触发快捷键。可以忽略输入控件中的按键,并跳过按住按键产生的重复事件:
document.addEventListener('keydown', (e) => {
const target = e.target;
if (
target instanceof HTMLElement &&
(target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName))
) {
return;
}
if (e.repeat) return;
const key = e.key.toLowerCase();
if (key === 'o') {
exportLevel();
} else if (key === 'p') {
const code = prompt('Paste your save code:');
if (code) loadFromCode(code);
}
});
排查顺序
- 打开浏览器开发者工具,查看按下
O或P时是否出现异常。也可以在分支开头临时添加console.log('O pressed'),确认监听器是否执行。 - 如果输入中文后导出失败,先换用 UTF-8 Base64 编解码函数。
- 如果快捷键只在页面的部分区域失效,检查焦点是否位于输入框或可编辑元素中。
- 如果出现
Invalid save code!,开发时查看console.error的输出,以区分 Base64 解码、JSON 解析和网格结构校验错误。
Base64 不提供保密或防篡改能力。如果需要防止关卡代码被查看或修改,需要另行设计机制。仅凭当前代码无法判断是否有这类需求。
备注:内容仅供参考。
