event.preventDefault() 与返回 false(无 jQuery)

Posted

技术标签:

【中文标题】event.preventDefault() 与返回 false(无 jQuery)【英文标题】:event.preventDefault() vs. return false (no jQuery) 【发布时间】:2013-09-29 01:25:56 【问题描述】:

我想知道event.preventDefault()return false 是否相同。

我已经完成了some tests,看来是

如果使用旧模型添加事件处理程序,例如

elem.onclick = function()
    return false;
;

然后,return false 会阻止默认操作,例如 event.preventDefault()

如果使用addEventListener添加事件处理程序,例如

elem.addEventListener(
    'click',
    function(e)
        return false;
    ,
    false
);

那么,return false 不会阻止默认操作。

所有浏览器都这样吗?

event.preventDefault()return false 之间还有更多区别吗?

我在哪里可以找到一些关于 return false 在某些情况下表现得像 event.preventDefault() 的文档(我在 MDN 中找不到)?


我的问题只是关于普通 javascript,而不是 jQuery,所以请不要将其标记为 event.preventDefault() vs. return false 的重复项,即使两个问题的标题几乎相同。

【问题讨论】:

Duplicate of ***.com/questions/1357118/… 如果您阅读了这个问题,您会注意到这是一个通用的 JS 问题,而不是 jQuery 特定的问题。 jQuery 仅用于使示例代码尽可能短/干净。 @RaYell 不,因为 jQuery 的 return false 与普通 JavaScript 的行为不同。此外,另一个问题没有任何答案来解释普通 JS 的区别(只有一个解释它的评论,但很难找到)。所以我认为最好有两个不同的问题。 【参考方案1】:

1.3.1 中的W3C Document Object Model Events Specification。事件注册接口声明EventListener中的handleEvent没有返回值:

handleEvent 每当发生该类型的事件时都会调用此方法 为其注册了 EventListener 接口。 [...] 不归路 价值

1.2.4 下。事件取消该文件还指出

通过调用事件的 preventDefault 来完成取消 方法。如果一个或多个 EventListener 在任何期间调用 preventDefault 事件流阶段默认动作将被取消。

这应该会阻止您在任何浏览器中使用返回 true / false 可能产生的任何效果并使用event.preventDefault()

更新

html5 规范实际上指定了如何处理不同的返回值。 Section 7.1.5.1 of the HTML Spec 声明

如果返回值为 WebIDL boolean false 值,则取消 事件。

除了“鼠标悬停”事件之外的所有内容。

结论

我仍然建议在大多数项目中使用event.preventDefault(),因为您将与旧规范以及旧浏览器兼容。只有当你只需要支持最前沿的浏览器时,返回false取消是可以的。

【讨论】:

此链接写于 2000 年。HTML5 规范:w3.org/TR/html5/webappapis.html#event-handler-attributes 看起来它处理许多事件的返回值(不是鼠标悬停):“如果返回值是 WebIDL 布尔 false 值,则取消事件” 从 chrome 中的一些快速测试来看,两者都返回 false 并且 event.preventDefault() not 停止传播。主要归功于@Oriol:参见stop propagation 与normal 这个小提琴比较了stopPropagation()preventDefault()return false的行为:jsfiddle.net/m1L6of9x。在现代浏览器上,后两者具有相同的行为。【参考方案2】:

这里有几个例子可以帮助人们更好地理解和解决他们的问题。

TL;DR

on* 事件处理程序(例如,按钮元素上的 onclick 属性):返回 false 以取消事件 addEventListener 是不同的 API,返回值(例如 false)被忽略:使用 event.preventDefault()onclick="<somejs>" 有其自身的潜在混淆,因为 <somejs> 被包装在 onclick 函数的主体中。 使用浏览器 devtools getEventListeners API 查看您的事件侦听器在您的事件处理程序未按预期运行时如何进行故障排除。

示例

此示例特定于带有<a> 链接的click 事件...但可以概括为大多数事件类型。

我们有一个带有js-some-link-hook 类的锚(链接),我们想要打开一个模式并阻止任何页面导航发生。

以下示例在 MacOS Mojave 上的 google chrome (71) 中运行。

一个主要的缺陷是假设 onclick=functionName 与使用 addEventListener 的行为相同

假设我们有一个锚标记(链接),我们想在启用 javascript 时使用 javascript 处理它。我们不希望浏览器在点击时跟随链接(“防止默认”行为)。

<a href="https://www.example.com/url/to/go/to/when/no/javascript"
   class="js-some-link-hook">click me!</a>

点击属性

function eventHandler (event) 
    // want to prevent link navigation
    alert('eventHandler ran');
    return false;


function addEventListenerToElement () 
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', eventHandler);

addEventListenerToElement();

然后在浏览器devtools控制台中运行:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

...你会看到:

function onclick(event) 
function eventHandler (event) alert('eventHandler ran'); return false;

这根本不起作用。当使用onclick= 时,您的处理函数被包装在另一个函数中。

您可以看到我的函数定义包含在但没有被调用,因为我指定了函数引用而没有调用它。即我们需要onclick="functionName()" 而不是onclick="functionName" 以确保在单击元素时运行functionName

进一步您可以看到,即使我的函数被调用并且我的函数返回 false...onclick 函数不会返回该 false 值...这是“取消”事件所必需的。

为了解决这个问题,我们可以将onclick 设置为return myHandlerFunc();,这样可以确保onclickmyHandlerFunc 返回返回值(false)。

您也可以从myHandlerFunc 中删除return false; 并将onclick 更改为myHandlerFunc(); return false;,但这不太有意义,因为您可能希望将逻辑保持在您的处理函数中。

注意使用 javascript 设置 onclick,当您直接在 html 中而不是使用 javascript 设置 onclick 时(如我的示例),onclick 属性值是类型字符串和一切正常。如果您使用javascript设置onclick,则需要注意类型。如果您说element.setAttribute('onclick', myHandlerFunc()) myHandlerFunc 将立即运行,结果将存储在属性中...而不是在每次单击时运行。相反,您应该确保将属性值设置为字符串。 element.setAttribute('onclick', 'return myHandlerFunc();')

现在我们看到了它是如何工作的,我们可以修改代码来做任何我们想做的事情。用于说明目的的奇怪示例(请勿使用此代码):

function eventHandler (e) 
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(e);
    return false;


function addEventListenerToElement () 
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', 'return ('+eventHandler+')(event);');

addEventListenerToElement();

您看到我们已经将 eventHandler 函数定义包装成字符串。具体来说:前面有return语句的自执行函数。

再次在 chrome devtools 控制台中:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

...显示:

function onclick(event) 
    return (function eventHandler (e) 
        // want to prevent link navigation
        alert('eventHandler ran');
        console.log(e);
        return false;
    )(event);

...是的,应该可以。果然,如果我们单击链接,我们会收到警报并关闭该页面无法导航或刷新的警报。

关于onclick的更多注意事项... 如果您想在事件发生时接收和使用event 参数,您应该注意它被命名为“事件”。您可以在处理程序中使用名称 event 访问它(可通过父 onclick 函数范围获得)。或者您可以构建您的处理程序以将event 作为参数(更适合测试)...例如onclick="return myEventHandler(event);" 或如您在前面的示例中看到的那样。

添加事件监听器

function eventHandler (ev) 
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;


function addEventListenerToElement () 
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);

addEventListenerToElement();

浏览器开发工具:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

结果:

function eventHandler (ev) 
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;

所以你已经可以看出区别了。使用addEventListener,我们不会被包裹在onclick 函数中。我们的处理程序直接接收event 参数(因此我们可以随意调用它)。此外,我们的return false 在这里处于“***”状态,我们不必担心像onclick 那样添加额外的返回语句。

所以看起来它应该可以工作。单击链接,我们会收到警报。关闭警报,页面导航/刷新。 即事件没有通过返回 false 来取消。

如果我们查找规范(参见底部的资源),我们会看到 addEventListener 的回调/处理函数不支持返回类型。我们可以返回任何我们想要的东西,但由于它不是浏览器 API/接口的一部分,它没有任何作用。

解决方案:使用event.preventDefault() 而不是return false;...

function eventHandler (ev) 
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');


function addEventListenerToElement () 
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);

addEventListenerToElement();

浏览器开发工具...

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
console.log(''+listener); // to avoid truncation of output

给...

function eventHandler (ev) 
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');

...正如预期的那样。

再次测试:

点击链接。 获取警报。 关闭警报。 没有页面导航或刷新发生...这是我们想要的。

因此,addEventListener 使用 event.preventDefault(),因为返回 false 什么都不做。

资源

https://www.w3.org/TR/dom41/#dom-eventtarget-addeventlistener 事件注册(例如 addEventListener) https://www.w3.org/TR/dom41/#callbackdef-eventlistener 回调/处理程序/侦听器定义。 注意 返回类型为 void。即返回值不是接口的一部分,没有任何作用。 https://www.w3.org/TR/dom41/#event 事件对象(例如 Event.preventDefault)

html5 规范 (https://www.w3.org/TR/html5/webappapis.html#events) 令人困惑,因为他们在示例中同时使用了 onclickaddEventListener,并且说如下:

一个事件处理器H和一个Event对象E的事件处理器处理算法如下:

...

    处理返回值如下:

...

如果返回值为 Web IDL boolean false 值,则取消事件。

所以这似乎暗示return false 取消了addEventListeneronclick 的事件。

但是,如果您查看他们对 event-handler 的链接定义,您会看到:

事件处理程序有一个名称,该名称始终以“on”开头,后跟它所针对的事件的名称。

...

事件处理程序以两种方式之一公开。

第一种方式,所有事件处理程序共有的,是作为事件处理程序 IDL 属性。

第二种方式是作为事件处理程序的内容属性。 HTML 元素上的事件处理程序和 Window 对象上的一些事件处理程序以这种方式公开。

https://www.w3.org/TR/html5/webappapis.html#event-handler

所以看来return false 取消事件确实只适用于onclick(或一般on*)事件处理程序,而不适用于通过addEventListener 注册的事件处理程序,它有不同的API。

由于 html5 规范未涵盖 addEventListener API(仅 on* 事件处理程序)...如果他们在示例中坚持使用 on* 样式的事件处理程序,就不会那么混乱了。

【讨论】:

【参考方案3】:

preventDefault、stopPropogation、return false 的区别

默认操作 - 控制事件引发时的服务器端操作。

假设我们有 div 控件,并且在其中我们有一个按钮。所以 div 是按钮的父控件。我们有按钮的客户端单击和服务器端单击事件。我们还有 div 的客户端点击事件。

在客户端按钮的点击事件中,我们可以通过以下三种方式控制父控件和服务器端代码的动作:

return false - 这仅允许控件的客户端事件。不触发父控件的服务器端事件和客户端事件。

preventDefault() - 这允许客户端事件的控件及其父控件。服务器端事件,即。不触发控件的默认操作。

stopPropogation() – 这允许控件的客户端和服务器端事件。不允许控件的客户端事件。

【讨论】:

你错了,return false 不会停止传播,所以父控件被触发 (demo)。此外,我不确定您所说的“服务器端点击事件”是什么意思。 @Beginners,请忽略这个答案。 关于服务器端事件的废话是什么? -1 我认为服务器端的东西正在考虑 ASP,您可以在服务器上处理事件。 在谈到 JavaScript 和事件时,没有“服务器端”。【参考方案4】:

return false 仅适用于 IE,event.preventDefault() 受 chrome 支持,ff...现代浏览器

【讨论】:

但在 Firefox 上,return false 在使用旧模型添加事件处理程序时的工作方式类似于 event.preventDefault()

以上是关于event.preventDefault() 与返回 false(无 jQuery)的主要内容,如果未能解决你的问题,请参考以下文章

反应复选框:event.preventDefault() 中断 onChange 函数 - 为啥?

TypeError:event.preventDefault 不是函数

event.preventDefault() 与返回 false(无 jQuery)

event.preventDefault() 与返回 false(无 jQuery)

jQuery event.preventDefault 的 Javascript 本机等效项 [重复]

使用 event.preventDefault() 后如何触发事件