鼠标事件延时切换插件


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实现的在当前窗口中漂浮框的代码
Mar 15 Javascript
jQuery编写widget的一些技巧分享
Oct 28 Javascript
javascript suggest效果 自动完成实现代码分享
Feb 17 Javascript
详解Angular开发中的登陆与身份验证
Jul 27 Javascript
基于javascript实现按圆形排列DIV元素(三)
Dec 02 Javascript
详解打造 Vue.js 可复用组件
Mar 24 Javascript
JavaScript实现选中文字提示新浪微博分享效果
Jun 15 Javascript
详解用webpack把我们的业务模块分开打包的方法
Jul 20 Javascript
jQuery+datatables插件实现ajax加载数据与增删改查功能示例
Apr 17 jQuery
微信小程序滑动选择器的实现代码
Aug 10 Javascript
浅析vue-cli3配置webpack-bundle-analyzer插件【推荐】
Oct 23 Javascript
vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作
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
缅甸的咖啡简史
2021/03/04 咖啡文化
Banner程序
2006/10/09 PHP
PHP使用file_get_content设置头信息的方法
2016/02/14 PHP
PHP中引用类型和值类型功能与用法示例
2019/02/26 PHP
laravel实现Auth认证,登录、注册后的页面回跳方法
2019/09/30 PHP
让任务管理器中的CPU跳舞的js代码
2008/11/01 Javascript
JavaScript中访问节点对象的方法有哪些如何使用
2013/09/24 Javascript
JavaScript模拟重力状态下抛物运动的方法
2015/03/03 Javascript
JavaScript Function函数类型介绍
2015/04/08 Javascript
js获取当前年月日-YYYYmmDD格式的实现代码
2016/06/01 Javascript
js获取当前时间(昨天、今天、明天)
2016/11/23 Javascript
jquery select2的使用心得(推荐)
2016/12/04 Javascript
jQuery 利用ztree实现树形表格的实例代码
2017/09/27 jQuery
JS实现的简单表单验证功能示例
2017/10/13 Javascript
详解Vue 中 extend 、component 、mixins 、extends 的区别
2017/12/20 Javascript
vue实现微信分享链接添加动态参数的方法
2019/04/29 Javascript
js 实现ajax发送步骤过程详解
2019/07/25 Javascript
layui 富文本图片上传接口与普通按钮 文件上传接口的例子
2019/09/23 Javascript
javascript设计模式 ? 简单工厂模式原理与应用实例分析
2020/04/09 Javascript
Vue如何实现监听组件原生事件
2020/07/03 Javascript
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
[01:36:17]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第一场 1月31日
2021/03/11 DOTA
Python实现对比不同字体中的同一字符的显示效果
2015/04/23 Python
实例解析Python的Twisted框架中Deferred对象的用法
2016/05/25 Python
如何将python中的List转化成dictionary
2016/08/15 Python
用python找出那些被“标记”的照片
2017/04/20 Python
python2.7实现复制大量文件及文件夹资料
2019/08/31 Python
python解压zip包中文乱码解决方法
2020/11/27 Python
初探CSS3中的calc()功能
2015/07/14 HTML / CSS
h5封装下拉刷新
2020/08/25 HTML / CSS
俄罗斯茶和咖啡网上商店:Tea.ru
2021/01/26 全球购物
构造器Constructor是否可被override?
2013/08/06 面试题
2014年文学毕业生自我鉴定
2014/04/23 职场文书
python中24小时制转换为12小时制的方法
2021/06/18 Python
MySQL高速缓存启动方法及参数详解(query_cache_size)
2021/07/01 MySQL
Nginx 匹配方式
2022/05/15 Servers