给 2048 页面加键盘支持,踩了几个小坑
上周给之前那个 2048 的小页面加键盘方向键支持,本来以为十分钟的事,结果断断续续折腾了一个多小时。记录一下过程,主要给自己看。
起因很简单:同事在手机上玩我部署的那个 2048(就是活动里部署的那个静态页),说手机上只能滑,但我加触摸事件的时候把 touchstart 的默认行为没拦好,页面整体跟着滚。先把触摸的事修了,顺手想把键盘操作也补上,毕竟平时在电脑上调试用方向键更顺手。
键盘这边的第一版我是这么写的:document.addEventListener("keydown", (e) => { if (e.key === "ArrowUp") move("up"); ... }); 跑起来发现两个问题。一是按方向键页面会跟着滚动,因为 2048 的页面比视口高一点,方向键默认就有滚动行为。这个好办,e.preventDefault() 加上就行,但我一开始只在 move() 里面加,没拦住,后来才反应过来默认滚动发生在事件处理里,得在监听器里直接拦。
二是我不小心把 move("down") 写成了 move("down" )(多打了个空格),函数里 switch 匹配不到,静默失败,格子完全不动,也没有任何报错。排查的时候 console 里干干净净,我还以为监听器没挂上,绕了一圈。这个给我的教训是 switch 匹配不到最好加个 default 分支打个 log,至少失败的时候知道自己失败在哪。
后来又遇到一个更隐蔽的:游戏结束后有个「再来一局」按钮,鼠标点它没问题,但键盘 gameover 之后按方向键还会触发 move,会在一个已经结束的棋盘上继续合并,把分数算乱。原因是我的 move 函数没有检查游戏状态。加了一行 if (isGameOver) return; 才算完。
另外还有个小细节,e.key 在某些输入法开着的时候会返回 Process 而不是方向键名,我自己的测试机没复现,同事的机器上有过一次方向键失灵。后来改成了 e.code(ArrowUp 这些值在 e.code 里是固定的),目前没再听到他说有问题。key 和 code 的区别我之前一直没分太清,这次算是被迫搞明白了一半——为什么输入法会吞掉 key 事件的具体原因我还没查清楚,先记在这里。
最后的新键盘部分大概就三十行,核心就是:拦默认滚动、用 e.code、move 前查状态。改完让同事又试了一遍,他说手机上的滚动问题修好了,键盘那边他笔记本上玩着没再出问题。
遗留两个小困惑:一个是为什么 preventDefault 必须放在监听器顶层而不是 move 函数里才能拦住滚动,我猜和事件默认行为触发时机有关,但没找到特别确凿的文档说明;另一个就是上面说的输入法 Process 的具体机制。以后有空再翻翻 MDN。
- 点赞
- 收藏
- 关注作者
评论(0)