分类导航菜单的前端细节

来源:互联网 发布:专业解封淘宝账号 编辑:程序博客网 时间:2024/06/06 02:25

很多电商网站在主页都有一个商品分类浏览的下拉菜单,如京东、当当等,但大多数的菜单为了不让菜单切换过于灵敏,在显示子菜单时会加入一定的延迟。亚马逊主页也有类似的菜单,不同于其他的网站,亚马逊上的菜单当鼠标从菜单的选项上滑过时,子菜单的显示速度是超快的,而且也不容易误选。如这篇文章,《揭秘》中提到的问题。

针对这种分类菜单的实现,下面以一个demo,通过3种实现方法来讨论一下其中的细节,更重要的是亚马逊的菜单是如何实现快速响应和用户体验都具备的效果。

示例网站:http://flycode.sinaapp.com/demos/jq-menu-aim/

一,原始实现

使用JS实现鼠标滑动到主菜单选项显示子菜单菜单这样的效果,如果只实现切换的功能,本身很简单,只需要在菜单选项绑定mouseover,mouseout事件,来控制子菜单的显示隐藏即可。

如图这样的菜单,在菜单项绑定mouse事件,来控制子菜单的display和hover效果即可。

代码片段:

$.fn.dropdown1 = function(option) {        var s = $.extend({            current: "hover"        },        option || {});        $.each(this, function() {            $(this).bind("mouseover", function() {                var _this = $(this);                _this.find('.i-list').show();                _this.find('h3').addClass('hover');            }).bind("mouseout", function() {                var _this = $(this);                _this.find('.i-list').hide();                _this.find('h3').removeClass('hover');                            })        })    };
但这样的实现会有一个问题,当用户想把鼠标从一个主菜单选项挪到一个子菜单选项时,子菜单会消失。如示例网站中的第一种情况。

二,改进实现

为解决以上的问题,需要在下拉菜单在显示子菜单时加入一定的延迟,使用setTimeout来实现。

需要注意的是,在使用setTimeout时,需要判断之前mouseover-mouseout这个过程是否执行完毕,如果还在执行,需要clearTimeout,否则在菜单项上快速晃动鼠标后,会出现延迟动画。可以在示例代码中,去掉demo2中的clearTimeout的判断代码看效果。

代码片段:

$.fn.dropdown2 = function(option) {        var s = $.extend({            current: "hover",            delay: 10        },        option || {});        $.each(this,        function() {            var timer1 = null,            timer2 = null,            flag = false;            $(this).bind("mouseover",            function() {                if (flag) {                    clearTimeout(timer2);                } else {                    var _this = $(this);                    timer1 = setTimeout(function() {                        _this.find('.i-list').show();                        _this.find('h3').addClass('hover');                        flag = true;                    },                    s.delay);                }            }).bind("mouseout",            function() {                if (flag) {                    var _this = $(this);                    timer2 = setTimeout(function() {                        _this.find('.i-list').hide();                        _this.find('h3').removeClass('hover');                        flag = false;                    },                    s.delay);                } else {                    clearTimeout(timer1);                }            })        })    };
三,两者结合更优雅的实现

以上两种方法,一个响应快速但容易误操作,一个不容易误操作但是响应会有延迟。亚马逊的下拉菜单结合了这两者的优点,响应迅速又不容易误操作,这是怎么实现的呢?

其实亚马逊的秘诀关键,是给菜单加上了一个下图中紫色三角形的缓冲地带。



当鼠标移动到紫色三角的范围时,二级菜单并不会立马变化,而是设定一个延迟时间。而当你直上直下地移动鼠标的时候,二级菜单则会很快变化,所以才会保证快速响应却不会误操作。
基本原理,在document上绑定mousemove事件,追踪鼠标移动的坐标,记录最后几次的坐标到一个数组,根据坐标位置计算图中三角形区域范围,在此范围内延迟更新子菜单。如果超出此区域,立即激活子菜单。

计算缓冲范围核心代码:





结合上面的代码,如下图,通过设置一个tolerance值,使鼠标在菜单项中移动的范围增大到两条蓝色线的范围内,鼠标在缓冲范围内移动时,

通过计算鼠标轨迹开始点和结束点到两个边界点upperRight、lowerRight的斜率,比较两个值,就可以判断鼠标轨迹是否在缓冲范围内,

如果在范围内,就设置一个延迟时间不会立刻更新子菜单,如果超出范围,就会立刻更新子菜单。



原创粉丝点击