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


84

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

我做了一些测试,看来

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

    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行为的文档(我在MDN中找不到)event.preventDefault()


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


重复的stackoverflow.com/questions/1357118/…如果您阅读此问题,您会注意到这是一个通用的JS问题,而不是jQuery特定的问题。jQuery仅用于使示例代码尽可能简短。
RaYell 2013年

13
@RaYell不,因为jQuery的return false行为与普通JavaScript的行为不同。而且,另一个问题没有任何答案可以解释纯JS的区别(只有注释可以解释它,但是很难找到)。因此,我认为最好有两个不同的问题。
Oriol

Answers:


55

W3C文档对象模型事件规范1.3.1。事件注册接口指出,handleEventEventListener中没有返回值:

handleEvent 每当发生事件类型为EventListener接口注册的事件时,都会调用此方法。[...]没有返回值

根据1.2.4。事件取消文档还指出

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

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

更新资料

HTML5规范实际上指定了如何对待不同的返回值。HTML规范的7.1.5.1节指出:

如果返回值是WebIDL布尔值false,则取消该事件。

除了“ mouseover”事件以外的所有事件。

结论

我仍然建议event.preventDefault()在大多数项目中使用,因为您将与旧规范兼容,从而与旧版浏览器兼容。仅当您只需要支持最新的浏览器时,返回false即可取消。


2
该链接写于2000年。HTML5规范:w3.org/TR/html5/webappapis.html#event-handler-attributes看起来它可以处理许多事件的返回值(而不是鼠标悬停):“如果返回值是WebIDL布尔值错误值,然后取消该事件”
Charles L.

并且通过chrome的一些快速测试,返回false和event.preventDefault()都不会停止传播。主要归功于@Oriol:请参阅停止传播正常情况
Charles L.

这拨弄比较的行为stopPropagation()preventDefault()以及return falsejsfiddle.net/m1L6of9x。在现代浏览器上,后两者具有相同的行为。
Erik Koopmans

5

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

TL; DR

  • on*事件处理程序(例如onclick,按钮元素上的属性):返回false以取消事件
  • addEventListener是不同的API,返回值(例如false)将被忽略:use event.preventDefault()
  • onclick="<somejs>"有其自身的潜在困惑,因为<somejs>它包装在onclick函数的主体中。
  • 使用浏览器devtools getEventListenersAPI可以查看如果事件处理程序的行为不符合预期,事件侦听器将如何解决问题。

该示例特定于click带有<a>链接的事件...但是可以推广到大多数事件类型。

我们有一个锚点(链接)与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>

onclick属性

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();确保从onclick返回返回值(false)myHandlerFunc

您也可以return false;从中删除frommyHandlerFunc并将其更改onclick为be,myHandlerFunc(); return false;但这意义不大,因为您可能希望将逻辑保留在处理程序函数中。

请注意,onclick使用javascript进行设置时,如果onclick直接在html中而不是在javascript中进行设置(例如我的示例),则onclick属性值为字符串类型,并且一切正常。如果onclick使用javascript进行设置,则需要注意输入。如果您说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);"或如您在前面的示例中看到的那样。

addEventListener

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();

浏览器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 eventHandler (ev) {
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;
}

这样您已经可以看到区别。有了addEventListener我们,我们就不会包装在onclick函数中。我们的处理程序event直接接收参数(因此我们可以随意调用它)。同样,我们return false在这里处于“最高层”,我们不必担心会添加诸如with的额外return语句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();

浏览器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 eventHandler (ev) {
    // want to prevent link navigation
    ev.preventDefault();
    alert('eventHandler ran');
}

...符合预期

再次测试:

  • 点击链接。
  • 得到警报。
  • 解除警报。
  • 没有页面导航或刷新发生...这就是我们想要的。

因此,addEventListener将其event.preventDefault()用作返回false不会执行任何操作。

资源资源

html5规范(https://www.w3.org/TR/html5/webappapis.html#events)使事情变得混乱,因为它们在示例中同时使用onclickaddEventListener,并表示以下内容:

事件处理程序H和事件对象E的事件处理程序处理算法如下:

...

  1. 处理返回值如下:

...

如果返回值是Web IDL布尔值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的事件处理程序。

由于addEventListenerhtml5规范未涵盖该API(仅on*事件处理程序),因此如果它们坚持使用on*示例中的样式事件处理程序,则不会造成混淆。


-2

preventDefault,stopPropogation和return false之间的区别

表显示差异

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

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

在客户端上单击按钮的事件时,我们可以使用以下三种方式控制父控件和服务器端代码的操作:

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

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

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


21
您错了,return false没有停止传播,因此触发了父控件(demo)。而且,我不确定“服务器端单击事件”是什么意思。
Oriol 2014年

6
@初学者,请忽略此答案。
pilau 2015年

4
服务器端事件有什么废话?-1
Mark Amery

我认为服务器端人员正在考虑ASP,您可以在服务器上处理事件。
安德鲁(Andrew)

5
在谈论JavaScript和事件时,没有“服务器端”。
rawpower

-12

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


9
但是在Firefox上的return false工作方式类似于event.preventDefault()使用旧模型添加事件处理程序时
Oriol 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.