如何处理同时支持触摸事件和指针事件的设备上的触摸事件,菜单中的子项不是父菜单的子项

How to handle touch events on devices that support both Touch and Pointer events with a menu with sub items that are not children of the parent menu

我在支持指针和触摸事件的设备上使用 mouseleavehover 时遇到问题。这些设备包括带鼠标和触摸屏的笔记本电脑。

我基本上只想禁用 mouseleave 和 hover,但问题是它是支持两者的设备,我找不到适当解释这个的文章,也没有标准。

我查看了以下 links:

Disable hover effects on mobile browsers

How to remove/ignore :hover css style on touch devices

jquery preventing hover function on touch

jQuery mouseleave for touch screen / tablets

Disable hover effects on mobile browsers

我们使用 DNN (DotNetNuke) 作为内容管理系统。我知道您可以使用令牌和 DDR 菜单构建自定义菜单,但这对于我想要实现的目标来说太复杂了。

我的简单方法是根据从我们的 ERP 数据库获取的数据构建子菜单,并在您将鼠标悬停在 DNN 页面 link 上时显示它,该页面 "disabled" 具有匹配的特定名称使用 jQuery.

在桌面设备上一切正常。 它还适用于使用 Chrome.

的触摸和指针设备

我在具有触摸和指针事件的平板设备上遇到 Edge 问题。当您点击 "Categories" 时会触发 onmouseleave,这将导致子菜单关闭。当您点击 "Categories" 菜单时,它会触发悬停事件。

更困难的是子菜单不是父菜单的直接子菜单,因此使用 CSS 选择器并不总是那么容易。目前我将模块放在菜单下方,这样它至少非常接近,这样我就可以使用绝对和相对定位让子菜单直接显示在 link 下方。在这里您会注意到我在一个 mouseleave 事件上添加了一个超时函数,以允许某人在他们的鼠标离开悬停事件时导航到子菜单。

这是菜单的屏幕截图。它包含可以显示的子类别,但我只想在支持触摸和点事件的设备上正确显示主菜单。

示例 JSFidle 代码

JSFidle: https://jsfiddle.net/Tig7r/e6k9cfj1/13/

HTML

<nav class="NavMenu">
  <ul class="ul_menu">
  <li class='item'><a href="#"><span>Home</span></a></li>
  <li class='item'><a><span>Categories</span></a></li>
  </ul>
</nav>


<div class="subLevel MegaMenuDiv" id="MegaMenuDiv">
  <div class="custom_megamenu_wrapper">
   <ul class="main-category-list has-children"><li><a href="javascript:void(0)" class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" style="">Accessories</a>
      <ul class="secondary-items">
      <li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Accessory Holders</a></li>
      <li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Whiteboard Starter Pack</a></li>
   </ul></li>
</ul>
 </div>
</div>

css

.NavMenu{
  width:100%;
  height:40px;
  background-color:red;
  color:white !important;
}

.NavMenu ul li{
  list-style:none;
  display:inline-block;
  padding:10px;
}

.ul_menu li a:link{
  color:white;
}

.ul_menu li a:hover{
  color:black;
}

#MegaMenuDiv{
  background:black;
  color:white;
  position:absolute;
  width:550px;
  display:none;
  min-height:300px;
}

.MegaMenuDiv a:link{
  color:white;
}

.displayHiddenMenu{
  display: block !important;
}

.main-category-list li{
  list-style:none;
}

.secondary-items{
  background: #31383e;
  position: absolute;
  top: 0;
  left: 150px;
  width: calc(80vw - 50%);
  height: auto;
  list-style: none;
  /* padding: 20px; */
  display: none;
  height: 92%;
  overflow-y: auto;
  padding-top: 0px;
  z-index: 1000;
  max-width: 840px;
  padding-top: 13px;
  line-height: 2;
}

.secondary-items a:link, .secondary-items a:visited{
  color:white !important;
}

JQUERY

$(document).ready(function () {

$(".item:contains(Categories)").hover(function () {
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {          
        } else {
            console.log('No class, adding class');
            $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    }); 

 /* Removes the submenu when the mouse moves away from categories */
 $('.item:contains(Categories)').on("mouseleave", function (event) {
       if ($('.MegaMenuDiv:hover').length > 0) {
       // do nothing
       } else {             
                $('.MegaMenuDiv').removeClass("displayHiddenMenu");
       }
});

$(".item:contains(Categories)").hover(function () {
    if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
      console.log('Item has class');
    } else {
      console.log('No class, adding class');
      $('.MegaMenuDiv').addClass("displayHiddenMenu");
    }
});

  $(".item:contains(Categories)").on("touchstart click", function () {
    if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
      $('.MegaMenuDiv').removeClass("displayHiddenMenu");
    } else {
      $('.MegaMenuDiv').removeClass("displayHiddenMenu");
      $('.MegaMenuDiv').addClass("displayHiddenMenu");
    }
  });

  $('.MegaMenuDiv').on("mouseleave", function () {
    console.log('Mouseleave remove class');
    $('.MegaMenuDiv').removeClass("displayHiddenMenu");
  });

//Code for child menu elements
  $('.MegaMenuLinkMainWithChildren').hover(function () {
        if ($(this).next().hasClass('displayHiddenMenu')) {
                //do nothing
        } else {
            $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
            $(this).next().addClass('displayHiddenMenu');
        }
});

$('.MegaMenuLinkMainWithChildren').on('touchstart click', function () {
        var secondaryitems = $(this).next();        
        if ($(secondaryitems).hasClass('displayHiddenMenu')) {

        } else {
            $('.MegaMenuLinkMainWithChildren').next().not(secondaryitems).removeClass('displayHiddenMenu');
            $(secondaryitems).addClass("displayHiddenMenu");
        }
});

});

他能更好地解决这个问题。我听过 clicks mouseeventstouchevents。因此希望它能在任何设备上工作。但是我没有在 Edge 上测试这个。希望对你有帮助。

您还可以收听所有 .NavMenu .item 元素并隐藏 .MegaMenuDiv(如果不是类别项),因为有人可能会不小心将鼠标悬停在类别项上。

// main menu
$(".item:contains(Categories)").on('mouseenter touchstart click', function(e) {
 
 // toggle MegaMenuDiv on click
 e.type == 'click' ? $('.MegaMenuDiv').toggleClass("displayHiddenMenu") : $('.MegaMenuDiv').addClass("displayHiddenMenu");
});

$('#MegaMenuDiv').on('click', function(e){
 if(e.target == $('#MegaMenuDiv').get(0)){
   $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
  }
}).on('mouseleave', function(){
  $('#MegaMenuDiv .secondary-items').removeClass('displayHiddenMenu');
 $('#MegaMenuDiv').removeClass("displayHiddenMenu");
});

// MegaMenuLinkMainWithChildren
$(".MegaMenuLinkMainWithChildren").on('mouseenter touchstart click', function() {
 // toggle MegaMenuDiv
  $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
  $(this).next().addClass('displayHiddenMenu');
});
.NavMenu{
  width:100%;
  height:40px;
  background-color:red;
  color:white !important;
}

.NavMenu ul li{
  list-style:none;
  display:inline-block;
  padding:10px;
}

.ul_menu li a:link{
  color:white;
}

.ul_menu li a:hover{
  color:black;
}

#MegaMenuDiv{
  background:black;
  color:white;
  position:absolute;
  width:550px;
  display:none;
  min-height:300px;
}

.MegaMenuDiv a:link{
  color:white;
}

.displayHiddenMenu{
  display: block !important;
}

.main-category-list li{
  list-style:none;
}

.secondary-items{
  background: #31383e;
  position: absolute;
  top: 0;
  left: 150px;
  width: calc(80vw - 50%);
  height: auto;
  list-style: none;
  /* padding: 20px; */
  display: none;
  height: 92%;
  overflow-y: auto;
  padding-top: 0px;
  z-index: 1000;
  max-width: 840px;
  padding-top: 13px;
  line-height: 2;
}

.secondary-items a:link, .secondary-items a:visited{
  color:white !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<nav class="NavMenu">
    <ul class="ul_menu">
        <li class="item">
            <a href="#">
                <span>
                    Home
                </span>
            </a>
        </li>
        <li class="item">
            <a>
                <span>
                    Categories
                </span>
            </a>
        </li>
    </ul>
</nav>
<div class="subLevel MegaMenuDiv" id="MegaMenuDiv">
    <div class="custom_megamenu_wrapper">
        <ul class="main-category-list has-children">
            <li>
                <a class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" href="javascript:void(0)" style="">
                    Accessories
                </a>
                <ul class="secondary-items">
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Accessory Holders
                        </a>
                    </li>
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Whiteboard Starter Pack
                        </a>
                    </li>
                </ul>
            </li>
            <li>
                <a class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" href="javascript:void(0)" style="">
                    Other
                </a>
                <ul class="secondary-items">
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Accessory
                        </a>
                    </li>
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Starter Pack
                        </a>
                    </li>
                </ul>
            </li>
        </ul>
    </div>
</div>

我尝试了一些代码并设法让它工作。 mouseleavehover 事件不会在触摸设备上触发,这使得它可以工作。

$(document).ready(function () {

var touched = false;

    $(".item:contains(Categories)").on("mouseenter click", function (e) {
        if (!touched) {
            e.type == 'click' ? $('.MegaMenuDiv').toggleClass("displayHiddenMenu") : $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    }).on('touchstart', function (e) {
        touched = true;
        setTimeout(function () {
            touched = false;
        }, 300);
        // do touchstart stuff (similar to click or not)
        // toggle MegaMenuDiv on click
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        } else {
            $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    });

    $('.MegaMenuDiv').on("mouseleave", function () {
        if (!touched) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        }
    });

    // MegaMenuLinkMainWithChildren - Show children items
    $(".MegaMenuLinkMainWithChildren").on('mouseenter touchstart click', function () {
        // toggle MegaMenuDiv
        $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
        $(this).next().addClass('displayHiddenMenu');
    });

    //Removes the sub-menu when hovering over other menu items
    $('.item').not(".item:contains(Categories)").hover(function () {
        console.log('Hovering over other items, remove class');
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        }
    });

    //Add a cursor the the pointer
    $(".item:contains(Categories)").css("cursor", "pointer");

});

这是最新的fiddle:https://jsfiddle.net/Tig7r/htLny8a7/1/