鼠标事件延时切换插件


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 基于原型的对象(创建、调用)
Oct 16 Javascript
js方法数据验证的简单实例
Sep 17 Javascript
JS查找字符串中出现最多的字符及个数统计
Feb 04 Javascript
React-Router如何进行页面权限管理的方法
Dec 06 Javascript
js 公式编辑器 - 自定义匹配规则 - 带提示下拉框 - 动态获取光标像素坐标
Jan 04 Javascript
Vue波纹按钮组件制作
Apr 30 Javascript
详解如何在Angular优雅编写HTTP请求
Dec 05 Javascript
详解iframe跨域的几种常用方法(小结)
Apr 29 Javascript
sortable+element 实现表格行拖拽的方法示例
Jun 07 Javascript
如何使用Node.js爬取任意网页资源并输出PDF文件到本地
Jun 17 Javascript
vue cli安装使用less的教程详解
Jul 12 Javascript
weui上传多图片,压缩,base64编码的示例代码
Jun 22 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 !function_exists("T7FC56270E7A70FA81A5935B72EACBE29"))代码解密
2011/01/07 PHP
php中的curl_multi系列函数使用例子
2014/07/29 PHP
PHP之autoload运行机制实例分析
2014/08/28 PHP
PHP使用CURL模拟登录的方法
2015/07/08 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
yii2.0框架实现上传excel文件后导入到数据库的方法示例
2020/04/13 PHP
JQuery Highcharts 动态生成图表的方法
2013/11/15 Javascript
利用javaScript实现点击输入框弹出窗体选择信息
2013/12/11 Javascript
javascript类型转换使用方法
2014/02/08 Javascript
js函数参数设置默认值的一种变通实现方法
2014/05/26 Javascript
纯js实现div内图片自适应大小(已测试,兼容火狐)
2014/06/16 Javascript
jQuery实现根据类型自动显示和隐藏表单
2015/03/18 Javascript
Bootstrap Chart组件使用教程
2016/04/28 Javascript
AngularJS表格详解及示例代码
2016/08/17 Javascript
在页面中引入js的两种方法(推荐)
2017/08/29 Javascript
Parcel 打包示例(React HelloWorld)
2018/01/16 Javascript
微信小程序实现两个页面传值的方法分析
2018/12/11 Javascript
JS实现的简单tab切换功能完整示例
2019/06/20 Javascript
three.js利用gpu选取物体并计算交点位置的方法示例
2019/11/25 Javascript
Vue的data、computed、watch源码浅谈
2020/04/04 Javascript
python实现得到一个给定类的虚函数
2014/09/28 Python
Python多线程编程之多线程加锁操作示例
2018/09/06 Python
Python正则表达式指南 推荐
2018/10/09 Python
Pandas统计重复的列里面的值方法
2019/01/30 Python
python障碍式期权定价公式
2019/07/19 Python
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
英国豪华家具和经典家居饰品购物网站:OKA
2020/06/05 全球购物
Linux面试题LINUX系统类
2015/11/25 面试题
remote接口和home接口主要作用
2013/05/15 面试题
工程资料员岗位职责
2014/03/10 职场文书
园林技术专业求职信
2014/07/28 职场文书
申报材料格式
2014/12/30 职场文书
英文慰问信范文
2015/03/24 职场文书
2019年干货:自我鉴定
2019/03/25 职场文书
公司致全体员工的感谢信
2019/06/24 职场文书
修改MySQL的默认密码的四种小方法
2021/05/26 MySQL