鼠标事件延时切换插件


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 相关文章推荐
设置下载不需要倒计时cookie(倒计时代码)
Nov 19 Javascript
Blocksit插件实现瀑布流数据无限( 异步)加载
Jun 20 Javascript
JS利用cookie记忆当前位置的防刷新导航效果
Oct 15 Javascript
JS组件Bootstrap dropdown组件扩展hover事件
Apr 17 Javascript
原生js实现addClass,removeClass,hasClass方法
Apr 27 Javascript
js自制图片放大镜功能
Jan 24 Javascript
JS获取本周周一,周末及获取任意时间的周一周末功能示例
Feb 09 Javascript
js正则表达式验证密码强度【推荐】
Mar 03 Javascript
如何把vuejs打包出来的文件整合到springboot里
Jul 26 Javascript
vue自定义tap指令及tap事件的实现
Sep 18 Javascript
详解vue2.0模拟后台json数据
May 16 Javascript
layui2.0使用table+laypage实现真分页
Jul 27 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中json_encode()和json_decode()
2014/05/25 PHP
php动态函数调用方法
2015/05/21 PHP
PHP基于yii框架实现生成ICO图标
2015/11/13 PHP
thinkPHP5.0框架应用请求生命周期分析
2017/03/25 PHP
passwordStrength 基于jquery的密码强度检测代码使用介绍
2011/10/08 Javascript
使用JS取得焦点(focus)元素代码
2014/03/22 Javascript
js检测iframe是否加载完成的方法
2015/11/26 Javascript
深入理解(function(){... })();
2016/08/16 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
在Vue项目中引入腾讯验证码服务的教程
2018/04/03 Javascript
利用jquery和BootStrap实现动态滚动条效果
2018/12/03 jQuery
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
2019/05/07 Javascript
Vue-CLI 3 scp2自动部署项目至服务器的方法
2020/07/24 Javascript
vue组件是如何解析及渲染的?
2021/01/13 Vue.js
[05:31]DOTA2上海特级锦标赛主赛事第三日RECAP
2016/03/05 DOTA
python实现随机密码字典生成器示例
2014/04/09 Python
python中常用的各种数据库操作模块和连接实例
2014/05/29 Python
Python实现返回数组中第i小元素的方法示例
2017/12/04 Python
解决Matplotlib图表不能在Pycharm中显示的问题
2018/05/24 Python
Python的argparse库使用详解
2018/10/09 Python
python实现图片识别汽车功能
2018/11/30 Python
Python数据类型之Set集合实例详解
2019/05/07 Python
Python 导入文件过程图解
2019/10/15 Python
调整Jupyter notebook的启动目录操作
2020/04/10 Python
Python3将ipa包中的文件按大小排序
2020/04/17 Python
Keras官方中文文档:性能评估Metrices详解
2020/06/15 Python
美国乡村商店:Plow & Hearth
2016/09/12 全球购物
意大利专业化妆品品牌:KIKO MILANO
2017/02/01 全球购物
命名空间(namespace)和程序集(Assembly)有什么区别
2015/09/25 面试题
软件工程专业推荐信
2013/10/28 职场文书
建房协议书
2014/04/11 职场文书
2014年党员评议表自我评价
2014/09/27 职场文书
党员三严三实对照检查材料
2014/10/13 职场文书
爱牙日宣传活动总结
2015/02/05 职场文书
2016中秋节月饼促销广告语
2016/01/28 职场文书
详解Android中的TimePickerView(时间选择器)的用法
2022/04/30 Java/Android