鼠标事件延时切换插件


Posted in Javascript onMarch 12, 2011

原理很简单:
onmouseover、onmouseout执行业务代码时使用setTimeout进行延时,第二次触发的时候先清除掉前面的setTimeout。
原理

var timer; 
document.getElementById('test').onmouseover = function () { 
clearTimeout(timer); 
timer = setTimeout(function () { 
alert('over') 
}, 150); 
}; 
document.getElementById('test').onmouseout = function () { 
clearTimeout(timer); 
timer = setTimeout(function () { 
alert('out') 
}, 150); 
};

上述代码可以看到,定时器返回值(唯一ID)由timer保存着,onmouseover与onmouserout都可以清除未执行的定时器,防止重复执行。这里timer让onmouseover与onmouserout有了一个“组”的概念,我们还可以让更多的元素能够访问到“组”,例如插入式的下拉菜单与tips等触发元素与弹出层都需要共用同一个timer,这样不会因为鼠标离开导致层被关闭(只要指针还在层上)。
封装事件
/*! 
* hoverDelay.js 
* http://www.planeArt.cn 
* Copyright 2011, TangBin 
* Dual licensed under the MIT or GPL Version 2 licenses. 
*/ 
(function (pluginName) { 
var id = 0, data = {}, 
addEvent = function (elem, type, callback) { 
if (elem.addEventListener) { 
elem.addEventListener(type, callback, false); 
} else { 
elem.attachEvent('on' + type, function () {callback.call(elem)}); 
}; 
}; 
this[pluginName] = function (elem, over, out, group, speed) { 
id ++; 
if (arguments.length === 0) return id; 
if (typeof arguments[1] !== 'function') return clearTimeout(data[arguments[1]]); 
if (typeof elem === 'string') elem = document.getElementById(elem); 
group = group || elem[pluginName] || id; 
speed = speed || 150; 
elem[pluginName] = group; 
addEvent(elem, 'mouseover', function () { 
var elem = this, 
fn = function () {over.call(elem)}; 
clearTimeout(data[group]); 
data[group] = setTimeout(fn, speed); 
}); 
addEvent(elem, 'mouseout', function () { 
var elem = this, 
fn = function () {out.call(elem)}; 
clearTimeout(data[group]); 
data[group] = setTimeout(fn, speed); 
}); 
}; 
})('hoverDelay');

data负责保存着自定义的“组”,同一“组”下甚至可以暂停mouseout的回调函数执行,这样可以实现套嵌操作。

接口说明

方法 参数 作用
hoverDelay (elem, over, out, group) 元素, 鼠标靠近时回调函数, 鼠标离开时回调函数, 设置延时分组名称[可选] 设置延时触发效果
hoverDelay (elem, group) 元素, 延时分组名称 停止鼠标离开执行的回调函数
hoverDelay () [无] 获取唯一延时分组名称
2011-01-22更新
我注意到jQuery API中关于hover事件的说明:
会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div中的图像),如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。
mouseout有BUG?这让我想起了我曾经工作中制作一个鼠标触发显示名片(类似腾讯微博的头像名片)经常被错误的执行了mouseout事件。于是我又查阅了jQuery的hover源码如何解决这个问题,发现它是使用“mouseenter”与“mouseleave”代替了“mouseover”与“mouseout”,“mouseenter”与“mouseleave”是IE(6、7、8)特有的的事件,标准浏览器并不支持,需要进行模拟,最终版本:
/*! 
* hoverDelay.js v1.1 
* http://www.planeArt.cn 
* Copyright 2011, TangBin 
* Dual licensed under the MIT or GPL Version 2 licenses. 
*/ 
(function (pluginName) { 
var id = 0, data = {}, 
addEvent = function (elem, type, callback) { 
if (elem.addEventListener) { 
if (type === 'mouseenter') { 
elem.addEventListener('mouseover', withinElement(callback), false); 
} else if (type === 'mouseleave') { 
elem.addEventListener('mouseout', withinElement(callback), false); 
} else { 
elem.addEventListener(type, callback, false); 
}; 
} else { 
elem.attachEvent('on' + type, function () {callback.call(elem, window.event)}); 
}; 
}, 
withinElement = function(callback) { 
return function (event) { 
var parent = event.relatedTarget; 
try { 
while (parent && parent !== this) parent = parent.parentNode; 
if (parent !== this) callback.apply(this, arguments); 
} catch(e) {}; 
}; 
}; 
this[pluginName] = function (elem, over, out, group, speed) { 
id ++; 
if (arguments.length === 0) return id; 
if (typeof arguments[1] !== 'function') return clearTimeout(data[arguments[1]]); 
if (typeof elem === 'string') elem = document.getElementById(elem); 
group = group || elem[pluginName] || id; 
speed = speed || 150; 
elem[pluginName] = group; 
addEvent(elem, 'mouseenter', function () { 
var elem = this, 
fn = function () {over.call(elem)}; 
clearTimeout(data[group]); 
data[group] = setTimeout(fn, speed); 
}); 
addEvent(elem, 'mouseleave', function () { 
var elem = this, 
fn = function () {out.call(elem)}; 
clearTimeout(data[group]); 
data[group] = setTimeout(fn, speed); 
}); 
}; 
})('hoverDelay');

查看1.1版演示
http://demo.3water.com/js/2011/hover/index.htm
新窗口打开

下载

1、原生版1.1
2、jQuery插件版

Javascript 相关文章推荐
Javascript下判断是否为闰年的Datetime包
Oct 26 Javascript
最简单的js图片切换效果实现代码
Sep 24 Javascript
网页源代码保护(禁止右键、复制、另存为、查看源文件)
May 23 Javascript
jquery mobile实现拨打电话功能的几种方法
Aug 05 Javascript
利用JS进行图片的切换即特效展示图片
Dec 03 Javascript
基于BootStrap Metronic开发框架经验小结【一】框架总览及菜单模块的处理
May 12 Javascript
jQuery事件绑定用法详解
Sep 08 Javascript
angularjs使用directive实现分页组件的示例
Feb 07 Javascript
js自定义Tab选项卡效果
Jun 05 Javascript
js编写简单的聊天室功能
Aug 17 Javascript
使用JSON格式提交数据到服务端的实例代码
Apr 01 Javascript
微信JSSDK实现打开摄像头拍照再将相片保存到服务器
Nov 15 Javascript
autoIMG 基于jquery的图片自适应插件代码
Mar 12 #Javascript
再谈javascript图片预加载技术(详细演示)
Mar 12 #Javascript
在jQuery1.5中使用deferred对象 着放大镜看Promise
Mar 12 #Javascript
使用jquery插件实现图片延迟加载技术详细说明
Mar 12 #Javascript
Jquery.LazyLoad.js修正版下载,实现图片延迟加载插件
Mar 12 #Javascript
javascript textarea光标定位方法(兼容IE和FF)
Mar 12 #Javascript
JavaScript全局函数使用简单说明
Mar 11 #Javascript
You might like
Php+SqlServer实现分页显示
2006/10/09 PHP
dedecms中常见问题修改方法总结
2007/03/21 PHP
PHP操作Memcache实例介绍
2013/06/14 PHP
php获取新浪微博数据API实例
2013/11/12 PHP
PHP计算百度地图两个GPS坐标之间距离的方法
2015/01/09 PHP
php redis实现文章发布系统(用户投票系统)
2017/03/04 PHP
详解php伪造Referer请求反盗链资源
2019/01/24 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
对于Form表单reset方法的新认识
2014/03/05 Javascript
jQuery使用slideUp方法实现控制元素缓慢收起
2015/03/27 Javascript
el表达式 写入bootstrap表格数据页面的实例代码
2017/01/11 Javascript
关于不同页面之间实现参数传递的几种方式讨论
2017/02/13 Javascript
Vue 源码分析之 Observer实现过程
2018/03/29 Javascript
原生nodejs使用websocket代码分享
2018/04/07 NodeJs
详解VUE中常用的几种import(模块、文件)引入方式
2018/07/03 Javascript
从零使用TypeScript开发项目打包发布到npm
2020/02/14 Javascript
JS如何生成动态列表
2020/09/22 Javascript
[04:09]显微镜下的DOTA2第十二期—NaVi美如画的团战
2014/06/23 DOTA
浅谈python 里面的单下划线与双下划线的区别
2017/12/01 Python
Django中Forms的使用代码解析
2018/02/10 Python
Python中协程用法代码详解
2018/02/10 Python
python 基本数据类型占用内存空间大小的实例
2018/06/12 Python
解决pandas .to_excel不覆盖已有sheet的问题
2018/12/10 Python
django的ORM操作 增加和查询
2019/07/26 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
美国第一香水网站:Perfume.com
2017/01/23 全球购物
美国转售二手商品的电子商务平台:BLINQ
2018/12/13 全球购物
什么叫应用程序域?什么是托管代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释?
2012/05/23 面试题
出国考察邀请函
2014/01/21 职场文书
试用期转正鉴定评语
2014/01/27 职场文书
交通安全责任书范本
2014/07/24 职场文书
客户答谢会活动方案
2014/08/31 职场文书
领导班子四风对照检查材料范文
2014/09/27 职场文书
2015年小学生新年寄语
2014/12/08 职场文书
Pytest中skip和skipif的具体使用方法
2021/06/30 Python
Java如何实现通过键盘输入一个数组
2022/02/15 Java/Android