Firefox 不会阻止分派的提交事件

IT技术 javascript html forms reactjs
2021-05-20 05:42:33

无语的拨弄情景再现

关键代码是:

class Form extends React.Component {
    handleSubmit(evt) {
        evt.preventDefault()

        var data = {}
        for (var i = 0; i < this.form.elements.length; i++) {
        var elt = this.form.elements[i]
          if (elt.name) {
            data[elt.name] = elt.value
          }
        }

        this.props.onSubmit(data)
        return false
    }

    submit() {
        if (this.form.checkValidity())
            this.form.dispatchEvent(new Event('submit'))
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit.bind(this)} ref={r => this.form = r}>
                {this.props.children}
            </form>
        )
    }
}

之后this.form.dispatchEvent()evt.preventDefault()handleSubmit()不工作在Firefox

如果您在 Chrome 中打开 fiddle(例如)并将数据输入到字段中,您将在控制台中看到它 - 防止调度事件将完美运行。

在 Firefox 中阻止不起作用 - 记录数据后页面立即重新加载(请参阅控制台中的“APP CONSTRUCTOR”)。

所以,问题很明显:如何避免这个错误?

1个回答

首先,这不是特定于react的问题。

如何避免这个错误?

{ cancelable: true }在这种情况下,该标志似乎阻止了 Firefox 重新加载页面。

this.form.dispatchEvent(new Event('submit', { cancelable: true }))

这是一个完整而简单的示例:

<!Doctype html>
<html>
  <head>
    <script type="text/javascript">
      document.addEventListener("DOMContentLoaded", function(event) {
        const form = document.querySelector('#testform');
        const button = form.querySelector('button');

        form.onsubmit = function (e) {
          e.preventDefault();
          e.stopPropagation();

          console.log('submitting the form ...');
          
          // return true;
          return false;
        };

        // https://developer.mozilla.org/en-US/docs/Web/API/Event/Event
        // cancelable: (optional) a Boolean indicating whether the event can be cancelled. The default is false.
        const submitEvent = new Event('submit', { 
          cancelable: true
        });

        // https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
        // The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.
        console.log('is event trusted', submitEvent.isTrusted) // false
        console.log('is event cancelable', submitEvent.cancelable) // true

        button.onclick = function () {
          console.log('button clicked');
          const cancelled = form.dispatchEvent(submitEvent);
          // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
          // The return value is false if event is cancelable and at least one of the event handlers which handled this event called Event.preventDefault(). Otherwise it returns true.
          console.log('is cancelled', !cancelled);
        }
      });
    </script>
  </head>
  <body>
    <form id="testform">
      <input type="hidden" name="a" value="b">
      <p>Hit the button a couple times, the page should not refresh.</p>
      <button type="button">click</button>
    </form>
  </body>
</html>

为什么会发生这种情况:

https://www.chromestatus.com/features/57188​​03933560832 根据 UI 事件规范,不受信任的事件(即由 JavaScript 创建的事件)不应调用默认操作。

如果您将可取消标志更改为 false 并在 Chrome 中尝试测试,它仍然可以工作,因为(据我所知)它仍然是一个不受信任的事件(不是由用户与 UI 的直接交互创建的)并且 Chrome 不会默认运行不受信任事件的处理程序。

但是,我不确定为什么 Firefox 仍然为不受信任的事件运行默认处理程序。