javascript - 为什么 jquery.blockUI 吞掉 onClick 事件?

标签 javascript backbone.js marionette jquery-blockui

摘要使用 jquery.blockUI 似乎隐藏/吞下/屏蔽按钮单击事件。

技术斯塔赫

  1. 脊梁和 Marionette
  2. Backbone .radio
  3. 下划线
  4. jquery
  5. jquery.blockUI

(所有最新版本)


应用程序

该应用程序由文本输入和按钮组成。

enter image description here

就 Backbone /Marionette 术语而言,有

  1. 有 2 个区域的俯 View
  2. 作为文本输入的容器 View
  3. 带有按钮的页脚 View
  4. 容器 View 由模型支持。
  5. 页脚有一个按钮,点击该按钮会发送一个backbone.radio事件。
  6. 此事件在顶 View 中拾取。

enter image description here

当用户离开文本输入时,将调用 API(服务器/后端)。在示例中,使用 Promise/setTimeout 来模拟调用。

在示例中,按钮调用 console.log。


代码

这是 JSFiddle Example on JSFiddle以及 JavaScript 代码下方

// ------------------------------------------------------------------
var Model = Backbone.Model.extend({

  defaults: {
    "SearchCriteria": {
      "Min": { "value": "abc123", "ReadOnly": true }
    }
  },


  async callBackend() {

    //$.blockUI(); //<----- uncomment this and the button click is swallowed

    await new Promise(resolve => setTimeout(resolve, 3000));

    $.unblockUI();
  }

});
// ------------------------------------------------------------------

// ------------------------------------------------------------------
var ContainerView = Marionette.View.extend({
  template: _.template('<div><label>Container</label></div><div><input id = "min" name = "min" type = "text"/></div>'),

  events: {
    'change': 'onChangeData',
  },

  async onChangeData(data) {
    console.log('start onChangeData');    
    await this.model.callBackend();
    this.render();
    console.log('end onChangeData');    
  }

});
// ------------------------------------------------------------------

// ------------------------------------------------------------------
var FooterView = Marionette.View.extend({
  template: _.template('<div><button class="btn-footer-test">Footer</button></div>'),

  events: {
    "click .btn-footer-test": () => {
      console.log('click test ...');
      Backbone.Radio.channel("maske").trigger("select:test");
    }
  },

});
// ------------------------------------------------------------------

// ------------------------------------------------------------------
var TopView = Marionette.View.extend({
  template: _.template("<div id='container'></div><div id='footer'></div>"),

  regions: {
    container: '#container',
    footer: '#footer'
  },

  events: {
    'change': 'onChangeData',
  },

  initialize() {
    this.listenTo(Backbone.Radio.channel("maske"), "select:test", this.onTest, this);
  },

  onRender() {
    this.showChildView('container', new ContainerView({
      model: new Model()
    }));
    this.showChildView('footer', new FooterView());
  },

  onChangeData(data) {
  },

  onTest() {
    //NOT called if jquery.blockUI present ******

    console.log('onTest');
  }
});
// ------------------------------------------------------------------

$(document).ready(function () {
  console.log('Start');
  const topView = new TopView();

  topView.render();
  $('body').append(topView.$el);
});

使用

用户像这样使用应用程序。用户

  1. 更改文本输入
  2. 并直接点击按钮(无需先按 Tab 键移出该字段!)

预期行为

  1. 文本输入的更改会触发更改事件。
    1. jquery.blockUI
    2. 异步调用
    3. jquery unblockUI
  2. 执行按钮的点击事件

实际行为

当 jquery.blockUI 函数存在时,不会执行按钮的单击事件。注释 jquery.blockUI 按钮单击事件发生,但在等待返回之前。


问题

  1. 我做错了什么?
  2. 为什么点击事件会被吞掉?

最佳答案

What am I doing wrong?

你的期望是错误的。 JavaScript 中没有隐式机制可以在异步事件完成后序列化另一个事件。您(开发人员)负责异步事件的同步。

Why is the click event swallowed?

Click事件火灾 when a mousedown and mouseup event occur on the same element 。这不是你的情况。事件顺序如下:

  1. mousedown<button>
  2. change<input> ;导致显示覆盖<div>通过blockUI
  3. mouseup叠加 <div>
  4. click在触发的元素的最近公共(public)父元素上 mousedownmouseup ,即<body>

从技术上讲,输入更改后似乎不可能单击按钮,因为覆盖显示在 mouseup 之前。 ,但是有一种方法。如果在显示覆盖层时单击并按住鼠标按钮并随后释放,click事件将在按钮上触发,但这不是您想要的。

尝试使用这个片段。它记录每个 mousedown , mouseup , clickchange事件。它注册异步change <input> 上的事件处理程序第一秒不执行任何操作,然后显示覆盖层,然后休眠 3 秒,最后隐藏覆盖层。您可以根据按下鼠标按钮的时间观察各种行为。

更改输入文本并快速单击按钮

button.mousedown
input.change
button.mouseup
button.click

更改输入文本,单击按钮并按住 1 秒,然后松开

button.mousedown
input.change
div.mouseup
body.click

更改输入文本,单击按钮并按住 4 秒(直到覆盖消失),然后松开

button.mousedown
input.change
button.mouseup
button.click

$(document).on('mousedown mouseup click change', e => {
  console.log(e.target.tagName.toLowerCase() + '.' + e.type);
});

$('input').change(async _ => {
  await new Promise(resolve => setTimeout(resolve, 1000));
  const $div = $('<div style="position:fixed; left:0; top:0; right:0; bottom:0; background-color:rgba(0,0,0,0.5); z-index:999">').appendTo('body');
  await new Promise(resolve => setTimeout(resolve, 3000));
  $div.remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="type something, then click the button" style="width:250px">
<button>Button</button>

你将很难解决这个问题,因为在正常情况下 click事件不会在按钮上触发,因此我建议您重新考虑您的用户界面。 为什么当你使用异步/ promise 时甚至会阻止用户界面?它的发明是为了避免阻塞。

关于javascript - 为什么 jquery.blockUI 吞掉 onClick 事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57116105/

相关文章:

javascript - 根据国家/地区重定向

javascript - Backbone 路由器.navigate如何传递动态ID

backbone.js - 使用 Jasmine 单独测试 Marionette 模块

backbone.js - 是否可以使用 marionette 将多个模型绑定(bind)到一个 View ?

javascript - 无法读取 null 的属性 'top'

javascript - 我的单选按钮不会响应悬停

javascript - 当请求不是来自链接时,IE 上的 Document.referrer 问题

javascript - 如何在其他功能中重定向到 Backbone 路由器

javascript - 主路由器在路由 ""末尾附加一个 #,导致 dom 引用 anchor 在 Backbone/Require 应用程序中不起作用

javascript - 在 Backbone 路由中匹配空路由和尾部斜杠?