多个同步事件javascript

时间:2017-08-29 00:17:33

标签: javascript jquery coldfusion

这可能是一个愚蠢的问题。我知道我有点绿。 我的任务是修改旧的旧系统导航。有两个导航栏。第二个只有搜索按钮。我被要求删除第二个导航栏,并将其替换为显示搜索功能的下拉列表。由于这个系统的年龄,我受限于我能改变的地方。我可以写的JS没有限制。他们在Adobe ColdFusion系统上运行jQuery 1.11.1(两个月前他们从1.3.2升级)

首先:单击目标时,mouseenter和click事件都会触发。 mouseenter首先开火。这会导致桌面上的问题对敏锐的查看者可见,但在移动设备上,这会产生可怕的可用性问题。答:根据我的理解,鼠标事件不会发生在移动设备上,而是适用于我。 B:由于mouseenter事件首先运行,它会在处理click事件之前激活closeDropDown函数。在closeDropDown运行时,其.on('click', f(...eventstuff...))会听到旨在触发openDropDown函数的打开点击,因此下拉列表无法打开。

这是功能。 console.log用于检查何时运行。

function openDropDown(){
    $('div.dropdown').parent().on('click.open mouseenter', function(event){

      $subject = $(this).find('.dropdown-menu')
      // console.log(event.type, $subject, "first o");

       if(!$subject.is(":visible")){
          // console.log($subject, 'second o');

          $subject.show()
       }else {
         if(event.type == 'click'){
           // console.log('third o');

            $subject.toggle()
        }
    }

    closeDropDown($subject)
    // console.log('open complete');
 })
}


function closeDropDown($x){
    // console.log('first c');

    $(document).on("click.close",function(e){
        // console.log("second c", e.type, "this type");

        if(!$(e.target).closest(".dropdown-menu").parent().length){
            // console.log("third c");

            if($x.is(":visible")){
              // console.log('forth c');
              $x.hide()
            }
        }

        $(document).off("click.close")
        // console.log('complete close');
    })
}

openDropDown()
onSearchClick()

我已阅读了一些希望获得帮助的帖子(例如thisthat

总之,我知道我需要压缩我的代码。我理解了一些解决此问题的方法(添加if(... are we on a mobile device...)或一些计数器/检查,以防止在关闭下拉列表时运行closeDropDown)

我真的想了解事件监听器的基本原理以及为什么在其他东西之前运行。

虽然有关如何解决这个问题的建议很好,但我希望了解我做错的基本原理。任何基本指针都非常有用。

值得注意的是:我刚看过这个:.is(':visible') not working。我将使用.is重写代码('可见')。

其他可能有用的事情: 当我的所有console.log都处于活动状态时,这是Chrome Dev Tools控制台。 首先,点击页面加载后.... enter image description here 下拉打开并快速关闭。

第二次点击.... enter image description here

谢谢!感谢您的所有帮助!

1 个答案:

答案 0 :(得分:2)

这是一个非常广泛的问题。我会尝试简洁。我不认为ColdFusion应该在这里标记,因为它似乎只与HTML / CSS / JS有关。

配置活动

首先,我想解决您配置脚本的方式。 您可能会从查看事件处理examples from jquery中受益。

大多数人都会创建如下事件。它只是说,点击任何ID为" alerter"的文档元素,运行警报功能。

// Method 1
$(document).on(click, "#alerter", function(event){
   alert("Hi!");
});

OR

// Method 2 
$(document).on("click", "#alerter", ClickAlerter); 

function ClickAlerter(event) {
    alert("Hi!"); 
}

这两种方法都是完全有效的。但是,我的意见第二种方法更具可读性和可维护性。它将事件委托与逻辑分开。

对于您的代码,我强烈建议删除事件分配和逻辑的混合。 (它至少删除了一层嵌套)。

顺便说一下,您的事件监听器似乎没有正确配置。请参阅jQuery中的the correct syntax和此示例。

$( "#dataTable tbody" ).on( "click", "tr", function() {
    console.log( $( this ).text() );
});

关于多项活动

如果对象上有多个事件侦听器,则它们将按照它们注册的顺序触发。 This SO question已经涵盖了这一点,并提供了一个示例。

然而,这并不意味着在鼠标中心之前会发生点击。因为鼠标必须逐字输入才能单击它,所以将首先触发mouseenter事件。换句话说,在考虑事件的顺序时,你至少有两个因素在起作用。

  1. 浏览器触发事件​​的顺序
  2. 他们的注册顺序
  3. 因此,并没有像#34;同时"事件,本身。当浏览器想要触发事件时会触发事件,并且它们将按照您分配的顺序浏览事件并触发匹配。

    如果要更改默认事件行为,则始终可以选择preventDefaultstopPropagation这些事件。这将停止浏览器的默认操作,并防止事件分别冒泡到父元素。

    关于移动鼠标事件

    鼠标事件绝对发生在移动设备上,并且假设它们没有安全性是不安全的。 This article深入介绍了被解雇事件的范围。引用:

      

    " [Y]在设计更高级的触摸交互时必须要小心:当用户使用鼠标时,它将通过点击事件进行响应,但是当用户触摸屏幕时,将发生触摸和点击事件。只需单击一下,事件的顺序为:

    touchstart
    touchmove
    touchend
    mouseover
    mousemove
    mousedown
    mouseup
    click
    

    我认为你会从阅读那篇文章中受益。它涵盖了有关移动和非移动环境中事件的常见问题和概念。再次,关于你的情况的相关陈述:

      

    有趣的是,在某些情况下,CSS:悬停伪类可以由触摸界面触发 - 点击一个元素使它:在手指关闭时处于活动状态,并且它还获得:悬停状态。 (使用Internet Explorer时,:悬停仅在用户手指关闭时生效 - 其他浏览器保持:悬停生效,直到下一次点击或鼠标移动。)

    示例

    我采用了所有这些概念并made an example on jsFiddle向您展示了其中的一些实际操作。基本上,我通过侦听touchstart事件并在这种情况下以不同方式处理click来检测用户是否正在使用触摸屏。因为我没有HTML,所以我必须创建一个原始界面。这些是指令:

    1. 我们需要确定用户是否有触摸屏
    2. 当用户悬停按钮时,菜单应显示
    3. 在移动设备上,当用户点击按钮时,菜单应该会出现
    4. 我们需要在用户点击按钮外部时关闭菜单
    5. 离开按钮应关闭菜单(移动或其他方式)
    6. 正如您将看到的,我在一个地方创建了所有活动:

      $(document).on("mouseover", "#open", $app.mouseOver);
      $(document).on("mouseout", "#open", $app.mouseOut);
      $(document).on("click", "#open", $app.click);
      $(document).on("touchstart", $app.handleTouch);
      $(document).on("touchstart", "#open", $app.click);
      

      我还创建了一个对象来包装所有逻辑,$app,这为我们提供了更大的灵活性和可读性。这是它的一个片段:

      var $app = $app || {}; 
      $app = {
      
        hasTouchScreen: false,
      
        handleTouch:function(e){
          // fires on the touchstart event
          $app.hasTouchScreen = true;
          $("#hasTouchScreen").html("true");
          $(document).off("touchstart", $app.handleTouch);     
        }, 
      
        click: function(e) {
          // fires when a click event occurrs on the button
          if ($app.hasTouchScreen) {
              e.stopPropagation();
              e.preventDefault();
              return;
          }
      
          // since we don't have a touchscreen, close on click.
          $app.toggleMenu(true);
        }, 
      
        touch: function(e) {
         // fires when a touchstart event occurs on the button
          if ($("#menu").hasClass("showing")) {
             $app.toggleMenu(true);
          } else {
             $app.toggleMenu();
          }    
        } 
      
      };