如何处理支持触摸和指针事件的设备上的触摸事件,其菜单包含不是父菜单的子项的子项
Posted
技术标签:
【中文标题】如何处理支持触摸和指针事件的设备上的触摸事件,其菜单包含不是父菜单的子项的子项【英文标题】: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 【发布时间】:2020-06-28 19:49:10 【问题描述】:我在支持 Pointer 和 Touch 事件的设备上遇到 mouseleave 和 hover 问题。这些设备包括带有鼠标和触摸屏的笔记本电脑。
我基本上只是想禁用鼠标离开和悬停,但问题是它是支持两者的设备,我找不到正确解释这一点的文章并且没有标准。
我查看了以下链接:
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 页面链接上时显示它,该链接已“禁用”,具有使用 jQuery 匹配的特定名称。
在桌面设备上一切正常。 它也适用于使用 Chrome 的触控和指针设备。
我在平板设备上遇到带有触控和指针事件的 Edge 问题。当您点击“类别”时会触发 onmouseleave,这将导致子菜单关闭。当您点击“类别”菜单时,它会触发悬停事件。
更困难的是子菜单不是父菜单的直接子菜单,因此使用 CSS 选择器并不总是那么容易。目前,我将模块放在菜单下方,使其至少非常靠近,以便我可以使用绝对和相对定位来使子菜单直接显示在链接下方。在这里您会注意到我在一个 mouseleave 事件上添加了一个超时功能,以允许某人在鼠标离开悬停事件时导航到子菜单。
这是菜单的屏幕截图。它包含可以显示的子类别,但我只想让主菜单在支持 Touch 和 Point 事件的设备上正确显示。
示例 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");
);
);
【问题讨论】:
【参考方案1】:我玩过一些代码并设法让它工作。 mouseleave 和 hover 事件不会在 Touch Devices 上触发,因此可以正常工作。
$(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");
);
这是最新的小提琴:https://jsfiddle.net/Tig7r/htLny8a7/1/
【讨论】:
【参考方案2】:他是解决问题的更好方法。我听过clicks
mouseevents
和touchevents
。因此希望可以在任何设备上工作。但是我没有在 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>
【讨论】:
感谢您提供更简洁的代码,我刚刚发现当您使用 Edge 在触摸设备上点击类别菜单项时,Mouseleave 会导致子菜单立即关闭。以上是关于如何处理支持触摸和指针事件的设备上的触摸事件,其菜单包含不是父菜单的子项的子项的主要内容,如果未能解决你的问题,请参考以下文章