# 浏览器默认行为 许多事件会自动触发浏览器执行某些行为。 例如: - 点击一个链接 —— 触发导航(navigation)到该 URL。 - 点击表单的提交按钮 —— 触发提交到服务器的行为。 - 在文本上按下鼠标按钮并移动 —— 选中文本。 如果我们使用 JavaScript 处理一个事件,那么我们通常不希望发生相应的浏览器行为。而是想要实现其他行为进行替代。 ## 阻止浏览器行为 有两种方式来告诉浏览器我们不希望它执行默认行为: - 主流的方式是使用 `event` 对象。有一个 `event.preventDefault()` 方法。 - 如果处理程序是使用 `on`(而不是 `addEventListener`)分配的,那返回 `false` 也同样有效。 在下面这个示例中,点击链接不会触发导航(navigation),浏览器不会执行任何操作: ```html autorun height=60 no-beautify Click here or here ``` 在下一个示例中,我们将使用此技术来创建 JavaScript 驱动的菜单。 ```warn header="从处理程序返回 `false` 是一个例外" 事件处理程序返回的值通常会被忽略。 唯一的例外是从使用 `on` 分配的处理程序中返回的 `return false`。 在所有其他情况下,`return` 值都会被忽略。并且,返回 `true` 没有意义。 ``` ### 示例:菜单 考虑一个网站菜单,如下所示: ```html ``` 下面经过 CSS 渲染的外观: [iframe height=70 src="menu" link edit] 菜单项是通过使用 HTML 链接 `` 实现的,而不是使用按钮 ` ``` 现在,除了该上下文菜单外,我们还想实现文档范围的上下文菜单。 右键单击时,应该显示最近的上下文菜单: ```html autorun height=80 no-beautify run

Right-click here for the document context menu

``` 问题是,当我们点击 `elem` 时,我们会得到两个菜单:按钮级和文档级(事件冒泡)的菜单。 如何修复呢?其中一个解决方案是:“当我们在按钮处理程序中处理鼠标右键单击事件时,我们阻止其冒泡”,使用 `event.stopPropagation()`: ```html autorun height=80 no-beautify run

Right-click for the document menu

``` 现在按钮级菜单如期工作。但是代价太大,我们拒绝了任何外部代码对右键点击信息的访问,包括收集统计信息的计数器等。这是非常不明智的。 另一个替代方案是,检查 `document` 处理程序是否阻止了浏览器的默认行为?如果阻止了,那么该事件已经得到了处理,我们无需再对此事件做出反应。 ```html autorun height=80 no-beautify run

Right-click for the document menu (added a check for event.defaultPrevented)

``` 现在一切都可以正常工作了。如果我们有嵌套的元素,并且每个元素都有自己的上下文菜单,那么这也是可以运行的。只需确保检查每个 `contextmenu` 处理程序中的 `event.defaultPrevented`。 ```smart header="event.stopPropagation() 和 event.preventDefault()" 正如我们所看到的,`event.stopPropagation()` 和 `event.preventDefault()`(也被认为是 `return false`)是两个不同的东西。它们之间毫无关联。 ``` ```smart header="嵌套的上下文菜单结构" 还有其他实现嵌套上下文菜单的方式。其中之一是拥有一个具有 `document.oncontextmenu` 处理程序的全局对象,以及使我们能够在其中存储其他处理程序的方法。 该对象将捕获任何右键单击,浏览存储的处理程序并运行适当的处理程序。 但是,每段需要上下文菜单的代码都应该了解该对象,并使用它的帮助,而不是使用自己的 `contextmenu` 处理程序。 ``` ## 总结 有很多默认的浏览器行为: - `mousedown` —— 开始选择(移动鼠标进行选择)。 - 在 `` 上的 `click` —— 选中/取消选中的 `input`。 - `submit` —— 点击 `` 或者在表单字段中按下 `key:Enter` 键会触发该事件,之后浏览器将提交表单。 - `keydown` —— 按下一个按键会导致将字符添加到字段,或者触发其他行为。 - `contextmenu` —— 事件发生在鼠标右键单击时,触发的行为是显示浏览器上下文菜单。 - ……还有更多…… 如果我们只想通过 JavaScript 来处理事件,那么所有默认行为都是可以被阻止的。 想要阻止默认行为 —— 可以使用 `event.preventDefault()` 或 `return false`。第二个方法只适用于通过 `on` 分配的处理程序。 `addEventListener` 的 `passive: true` 选项告诉浏览器该行为不会被阻止。这对于某些移动端的事件(像 `touchstart` 和 `touchmove`)很有用,用以告诉浏览器在滚动之前不应等待所有处理程序完成。 如果默认行为被阻止,`event.defaultPrevented` 的值会变成 `true`,否则为 `false`。 ```warn header="保持语义,不要滥用" 从技术上来说,通过阻止默认行为并添加 JavaScript,我们可以自定义任何元素的行为。例如,我们可以使链接 `
` 像按钮一样工作,而按钮 `