hover时显示可跟随鼠标移动的浮动框,运用函数节流与去抖进行优化
在很多笔试面试题中总能看到js函数去抖和函数节流,看过很多关于这两者的讨论,最近终于在一个需求中使用了函数去抖(debounce)和函数节流(throttle)。
需要完成的效果是,鼠标在表格的单元格上时,显示一个浮动框,并且浮动框会随鼠标移动。
这是效果图,没有做成动图,应该都能想象出来:
基本效果很容易实现,用单元格的hover事件控制浮动框的显示;鼠标移出单元格,即mouseout事件触发浮动框的隐藏;
而浮动框跟随鼠标移动的效果则用mousemove事件,监听鼠标的位置,同时改变浮动框的位置。
直接放公司项目的代码,懒癌晚期...
html结构
1.页面表格
2.浮动框:
3.浮动框的css:
注意将浮动框的定位设为fixed,z-index设大一点,能置于顶层就ok了。其他样式根据需要来写。
js部分
$(document).ready(function(){
//鼠标滑过表格单元格显示浮动框
var showFloatTimer=null;
$('.table-to-float tbody tr td').hover(
function(){
clearTimeout(showFloatTimer);
showFloatTimer=setTimeout(function(e){
$('.float-wp').fadeIn(200);//浮动框淡出
},300);
}
);
$('.table-to-float tbody tr td').mouseout(function(){
$('.float-wp').hide();
clearTimeout(showFloatTimer);//鼠标滑出时清除函数去抖中的定时事件
});
$('.table-to-float tbody tr td').mousemove(floatMove());
//floatMove()运行后返回一个函数对象,或什么都不返回
function floatMove(){//节流函数
var canRun=true;
return function(e){//e是mousemove的event参数
if(!canRun){return;}//如果有一个定时方法,直接返回
canRun=false;
setTimeout(function(){
var top = e.pageY+15;
var left = e.pageX+15;
$('.float-wp').css({
'top' : top + 'px',
'left': left+ 'px'
});
console.log("改变浮框位置");
canRun=true;
},150);
}
}
});
没有加函数节流和函数去抖之前,会出现以下问题:
1.当鼠标无意滑过表格单元格时,浮动框也会显示,每滑过一个单元格闪现一次;
2.快速滑过单元格时,触发hover事件,但是mouseout事件不会执行,导致浮动框不消失。
3.mousemove监听频率高,消耗系统资源。
为了解决这三个问题,增加了去抖和节流函数
概念:
函数去抖:当动作频繁触发时,只触发最后一次。
函数节流:当动作频繁触发时,隔一段时间触发一次,以降低触发频率。
代码解释:
因此,解决第一个问题运用了函数去抖,当鼠标停在一个单元格时显示浮动框,在此之前经过的单元格都不会触发浮动框显示事件。
为了解决第二个问题,对函数去抖的封装写法做了一点改动,将显示浮动框的定时器设为全局,在鼠标滑出时清除,这样就保证了滑出之后没有浮动框可以再显示。
第三问题运用函数节流来解决,降低mousemove的触发频率
没有运用函数节流之前,将鼠标滑过一个单元格的高度的距离,函数执行了30次左右
加了节流函数之后,执行次数仅为7次
在这个地方,被event参数的传递困扰了好久,因为没有意识到 floatMove() 运行之后要么返回函数对象,要么返回空
一直在研究如何将event先传入floatMove内,再传入回调函数内
冷静了一会儿之后再想想
$('.table-to-float tbody tr td').mousemove(floatMove());
这样写,当 floatMove() 运行返回函数对象时,就相当于直接在mousemove里写回调函数,所以直接在floatMove中return函数对象的地方接收参数就可以了。