在实现类似 Vim 的热键时遇到问题

Having Trouble Implementing Vim-like Hotkeys

我正在尝试为我的项目实现类似 Vim 的热键;首先,我决定实现 jk 绑定,所以我写了这个 KeyboardEvent 处理程序:

window.onkeydown = function( event ) {
    if (event.code === 'KeyJ')
        window.scrollBy({ top: 128, behavior: 'smooth' });

    else if (event.code === 'KeyK')
        window.scrollBy({ top: -128, behavior: 'smooth' });
};

似乎是合法的,对吧?实际上 — 不:当我 holding jk 滚动过程变得脱节和撕裂(也是似乎滚动速度减半,就像 64 将被添加到 scrollTop 而不是 128).

我能以某种方式直接将 k 映射到 并将 j 映射到 使用 plain JavaScript?


我已经试过了 solution:

const ArrowUp = new KeyboardEvent( 'keydown', { code: 'ArrowUp' } );
const ArrowDown = new KeyboardEvent( 'keydown', { code: 'ArrowDown' } );

window.onkeydown = function( event ) {
    if (event.code === 'KeyJ')
        window.dispatchEvent( ArrowDown );

    else if (event.code === 'KeyK')
        window.dispatchEvent( ArrowUp );
};

但它根本不起作用,我什至没有收到任何错误。

我有两个解决方案。第一个解决方案有点......我们只能说它不是很好。 您可以强制它每隔一段时间只监听事件以防止出现故障。

var lastScrollTime = Date.now();
window.onkeydown = function( event ) {
    var d = Date.now();
    if(d - lastScrollTime < 64){
        return;
    }
    lastScrollTime = d;
    if (event.code === 'KeyJ')
        window.scrollBy({ top: 128, behavior: 'smooth' });

    else if (event.code === 'KeyK')
        window.scrollBy({ top: -128, behavior: 'smooth' });
};

我的第二个解决方案稍微好一点,但仍然不是很好。您可以实现自己的平滑滚动系统。

var scrollTo = 0;
function lerpTo(){
    var newPt = lerp(scrollTo, window.scrollY, 1.1);
    console.log(newPt);
    window.scrollBy(0, window.scrollY - newPt);
}
function lerp(v0, v1, t) {
    return v0*(1-t)+v1*t
}
setInterval(lerpTo, 20);

然后,您只需按 j 或 k 更改 'scrollTo'。现在该代码使用了 lerp 函数。如果您想要更一致的运动,您可以按固定数量更换它。那个最大的缺点是你不能再正常滚动了。要重新添加正常滚动,您必须监听该事件并再次设置滚动,但我认为这是一个糟糕的解决方案。或者,要再次添加正常滚动,您可以在手动滚动时禁用 lerp 代码,然后在有人按 j 或 k 时重新启用它。