竖排主菜单鼠标滑动角度判断显示子分类
在较多电商类网站中,总会有竖排主类别菜单,鼠标滑动右侧显示分类下的详细类别,但因为是竖排分类,就可能会出现鼠标滑动时,只是想单纯的在露出的详细分类下,点击当前分类下的某个分类,但是因为鼠标滑动经过了其他分类,子分类菜单就被切换走了,只能鼠标平移至右侧,用户体验是极不好的。
比如下图在选择了 “女鞋/箱包/钟表/珠宝” 这个分类后, 鼠标正常从上方按箭头方向滑动到 “2017新品” 时, 在不做角度等辅助判断下,鼠标因为经过了 “美妆个护/宠物” 菜单后,右侧的分类就被切换走了(右侧显示了 “美妆个护/宠物” 的子分类),选右侧的东西完全靠鼠标平移,想想心也是塞的呢。
所以在这种情况下,我们需要对鼠标滑动的角度 和 停留时间进行判断,判断用户想要的操作是否是切换至其他分类,来进行切换。
从两个方面来判断切换最为稳妥,判断鼠标滑动角度 和 鼠标停留时长。
判断鼠标滑动角度
对于角度的计算考虑到各种数值约等于其实蛮复杂的,我觉得(什么正弦、余弦的,想想脑袋都大了),所以可以依靠斜率来判断角度,看是否进行切换。
记录鼠标移动的初识位置 A 和 最终位置B 的坐标,以初始位置为圆心做坐标轴,计算两点构成直线的斜率(Kab)进行下一步的操作。
在 起始位置 A 建立坐标轴,参照下图,对 最终位置 所在位置应当触发的情况进行逻辑梳理:
1.不需要进行菜单切换
当鼠标最终位置在坐标系 1 , 2 区域, 默认菜单栏在主菜单右侧,虽然鼠标方向是向下或者向上进行了滑动,但是我们先默认用户是想点击右侧子菜单下方和上方的项目,所以暂不进行切换。
当鼠标最终位置在坐标轴 X轴上时,因为左右区域都算是 当前主菜单栏目的子元素,所以也不进行切换。
2.需要进行菜单切换
当鼠标最终位置在坐标系 3, 4 区域, 默认菜单栏在主菜单右侧,因为鼠标方向是向左下或者向左上进行了滑动,没有任何往右侧子菜单移动的意图,所以是进行切换。
当鼠标最终位置在坐标轴 Y轴上时,垂直上下的移动表明用户就是想切换菜单,所以进行切换。
3.隐藏分类
当鼠标在menu区域移除时,当前展示的子菜单应当隐藏不在显示。
根据上面的逻辑梳理,我们编写以下核心逻辑代码:
1 $(document).ready(function(){ 2 var site = []; //定义一个数组存储位置信息 3 //监听鼠标移动获取位置信息 4 $(document).mousemove(function(e){ 5 var e = e ? e:window.event; 6 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 7 var scrollY = document.documentElement.scrollTop || document.body.scrollTop; 8 var x = e.pageX || e.clientX + scrollX; 9 var y = e.pageY || e.clientY + scrollY; 10 //将获取的 位置信息以 坐标的形式,存储在 site 数组中 11 site.push({ 12 x : x, 13 y : y 14 }); 15 //只存储三个位置信息,超出删除第一个元素 16 if(site.length > 3){ 17 site.shift(); 18 } 19 20 }); 21 22 //计算斜率 返回是否切换分类 23 var getSlope = function(set){ 24 var len = site.length; 25 //只去数组中第一个和最后一个位置信息 做初识坐标和最终坐标 26 if(len > 2){ 27 var siteArr = { 28 x1 : site[0].x, 29 y1 : site[0].y, 30 x2 : site[len-1].x, 31 y2 : site[len-1].y 32 } 33 //如果鼠标进行了 竖向平移 或 横向平移 或 近乎于纵向平移 时正常进行切换,不进行接下来的判断 34 if(siteArr.x1 == siteArr.x2 || siteArr.y1 == siteArr.y2 || Math.abs(siteArr.x2 - siteArr.x1) <= 10){ 35 return 0; 36 } 37 //我们以鼠标初始位置 坐标所在的垂直竖线为基线 ,若鼠标移动的方向在 基线左侧,而我们的子菜单在右侧,说明用户想要切换主菜单,所以也正常进行切换,不进行接下来的判断 38 if(siteArr.x2 < siteArr.x1){ 39 return 0; 40 } 41 //set 为当前主菜单栏目项,我们判断鼠标的起始位置是否在主菜单栏目的外的左侧和栏目外的右侧,如果在说明用户刚移入主菜单,应进行切换,不进行接下来的判断 42 if(siteArr.x1 < set.left || siteArr.x1 > set.lx){ 43 return 0; 44 } 45 //求斜率 46 var k = (siteArr.y2-siteArr.y1)/(siteArr.x2-siteArr.x1); 47 //如果斜率不为0 则夹角不为0,则不进行切换 48 if(k){ 49 return 1; 50 } 51 }else { 52 return 0; 53 } 54 } 55
判断鼠标停留时长
当用户在主菜单一个子栏目中停留300ms,我们就认为用户是想进行切换查看其它子菜单。
所以之前上面👆提到的暂不切换的情况:当 最终位置在坐标系1,2区域时,暂不进行切换,但如果鼠标停留时间大于300ms则需要进行切换。
切换显示子菜单主要代码:
在显示切换菜单方法中调用 getSlope 方法 并将当前 主菜单的栏目元素 传给 getSlope(set),其余看备注吧。
1 var hideTime = 0; //定时器时间 2 var flag; //是否切换标识,0则切换,1不切换 3 $(".menuContent .item").mouseenter(function(){ 4 var self = $(this); 5 var obj = []; 6 var set = { 7 left : self.offset().left, 8 top : self.offset().top, 9 lx : self.offset().left + self.outerWidth(), 10 ty : self.offset().top + self.outerHeight() 11 } 12 flag = angle.getSlope(set); //调用上面的方法,0则切换,1不切换 13 clearTimeout(hideTime); //清除定时器 14 15 //如果flag为0说明需要切换,去除当前选中及显示子菜单样式,切换至新子菜单 16 if(!flag) { 17 clearTimeout(hideTime); 18 $(".menuContent .item").removeClass('js-menu-item-on'); 19 self.addClass('js-menu-item-on'); 20 $(".submenu").hide(); 21 var selector = self.attr('data-id'); 22 $('.'+selector).show(); 23 24 } 25 //如果flag为1则不进行切换,但如果用户鼠标停留时长大于300ms则进行切换 26 else { 27 var cur = this; 28 var pre = $(".menuContent").find('.js-menu-item-on')[0]; 29 hideTime = setTimeout(function(){ 30 if(pre != cur){ 31 $(".menuContent .item").removeClass('js-menu-item-on'); 32 self.addClass('js-menu-item-on'); 33 $(".submenu").hide(); 34 var selector = self.attr('data-id'); 35 $('.'+selector).show(); 36 } 37 },300); 38 } 39 })
虽然只是一个分类菜单显示切换,但好的用户体验也是需要的不是~
嗯,核心是判断鼠标滑动角度 和 鼠标停留时间来进行切换。
jd首页的子菜单就有这种优化,可以试试,就知道我在这瞎白活什么了。🤣
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?