Chrome 55 中即将推出 auxclick

杰夫·波斯尼克
Jeff Posnick

什么情况下点击不是 click?对于开发复杂界面的 Web 开发者来说,这不是一个抽象的哲学问题。如果您要实现自定义鼠标输入行为,请务必牢记用户意图。例如,如果用户使用鼠标中间的按钮点击链接,那么可以合理假设他们想要打开一个包含该链接内容的新标签页。如果用户中键点击了一个随机界面元素,那么您可能希望认为这是无意间的输入,并忽略相应输入,而点击主按钮应该会触发来自界面的响应。

您可以通过单个 click 事件监听器对这些精细互动进行建模(如果工作起来有点麻烦)。您必须明确检查 MouseEventbutton 属性,查看该属性是否设置为 0(表示主按钮),而非任何其他按钮(1 通常表示中间按钮),依此类推。但很少有开发者会明确检查 button 属性,从而导致代码无论按哪个按钮,都能以相同的方式处理所有 click

从 Chrome 55 开始,系统会触发一种名为 auxclick 的新型 MouseEvent,以响应使用非主要按钮进行的任何点击。伴随这个新事件是 click 事件的行为变化:它仅在用户按下鼠标主按钮时触发。我们希望这些更改能够让 Web 开发者更轻松地编写事件处理脚本,从而仅响应自己关注的点击类型,而无需专门检查 MouseEvent.button 属性。

减少误报

如前所述,创建 auxclick 的一个动机是避免部署会错误地替换“medium-click-opens-a-tab”行为的自定义 click 处理程序。例如,假设您已编写了一个 click 事件处理脚本,它使用 History API 重写地址栏并实现自定义单页导航。可能如下所示:

document.querySelector('#my-link').addEventListener('click', event => {
    event.preventDefault();
    // ...call history.pushState(), use client-side rendering, etc....
});

当由鼠标的主按钮触发时,您的自定义逻辑可能会按预期运行,但如果该代码在用户点击中键时运行,则实际上是假正例。在新行为之前,最终会阻止打开新标签页的默认操作,该操作的运行与用户预期的相反。虽然您可以在处理程序开始时明确检查 event.button === 0,并且仅在出现这种情况时才执行代码,但很容易忘记或永远不会意识到有必要这样做。

仅运行您需要的代码

误报更少的相反,auxclick 回调仅在实际存在非主要鼠标按钮时才会运行。例如,如果您的代码需要在打开新标签页之前计算合适的目标网址,您可以监听 auxclick 并将该逻辑包含在回调中。点击主鼠标按钮时,它不会产生运行开销。

浏览器支持和兼容性

这一新行为目前仅在 Chrome 55 中实现。正如初始方案中所述,我们非常欢迎 Web 开发者社区提供反馈(包括正面和负面)。提交 GitHub 问题是与从事标准化流程的人员分享这些反馈的最佳方式。

同时,开发者不必再等待 auxclick 的广泛发布,从而遵循一些有关处理鼠标事件的最佳实践。如果您花时间在 click 事件处理脚本开始时检查 MouseEvent.button 属性的值,可以确保采取适当的操作。无论是否支持 auxclick,以下模式都将以不同方式处理主要点击和辅助点击:

function handlePrimaryClick(event) {
    // ...code to handle the primary button click...
}

function handleAuxClick(event) {
    // ...code to handle the auxiliary button click….
}

document.querySelector('#my-link').addEventListener('click', event => {
    if (event.button === 0) {
    return handlePrimaryClick(event);
    }


    // This provides fallback behavior in browsers without auxclick.
    return handleAuxClick(event);
});

// Explicitly listen for auxclick in browsers that support it.
document.querySelector('#my-link').addEventListener('auxclick', handleAuxClick);