鼠标事件延时切换插件


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中各种trim的实现详细解析
Dec 10 Javascript
jquery制作多功能轮播图插件
Apr 02 Javascript
使用JavaScript为一张图片设置备选路径的方法
Jan 04 Javascript
layui选项卡效果实现代码
May 19 Javascript
关于Vue背景图打包之后访问路径错误问题的解决
Nov 03 Javascript
jquery 给动态生成的标签绑定事件的几种方法总结
Feb 24 jQuery
浅谈React高阶组件
Mar 28 Javascript
微信小程序使用for循环动态渲染页面操作示例
Dec 25 Javascript
mock.js模拟数据实现前后端分离
Jul 24 Javascript
vuex实现数据状态持久化
Nov 11 Javascript
使用Promise封装小程序wx.request的实现方法
Nov 13 Javascript
JavaScript实现矩形块大小任意缩放
Aug 25 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
用 PHP5 轻松解析 XML
2006/12/04 PHP
Linux下编译redis和phpredis的方法
2016/04/07 PHP
laravel-admin的多级联动方法
2019/09/30 PHP
对laravel in 查询的使用方法详解
2019/10/09 PHP
laravel 解决路由除了根目录其他都404的问题
2019/10/18 PHP
在网页中控制wmplayer播放器
2006/07/01 Javascript
用JS提交参数创建form表单在FireFox中遇到的问题
2013/01/16 Javascript
php 中序列化和json使用介绍
2013/07/08 Javascript
JavaScript中跨域调用Flash的方法
2014/08/11 Javascript
JavaScript数组去重的3种方法和代码实例
2015/07/01 Javascript
AngularJS基础 ng-focus 指令简单示例
2016/08/01 Javascript
js实现点击每个li节点,都弹出其文本值及修改
2016/12/15 Javascript
Vue 创建组件的两种方法小结(必看)
2018/02/23 Javascript
vue-router3.0版本中 router.push 不能刷新页面的问题
2018/05/10 Javascript
jQuery使用动画队列自定义动画操作示例
2018/06/16 jQuery
vue实现动态显示与隐藏底部导航的方法分析
2019/02/11 Javascript
[02:16]DOTA2英雄基础教程 干扰者
2014/01/15 DOTA
[01:50]2014DOTA2西雅图邀请赛 专访欢乐周宝龙
2014/07/08 DOTA
Python输出PowerPoint(ppt)文件中全部文字信息的方法
2015/04/28 Python
Python中使用hashlib模块处理算法的教程
2015/04/28 Python
Python安装官方whl包和tar.gz包的方法(推荐)
2017/06/04 Python
Django查询数据库的性能优化示例代码
2017/09/24 Python
学习python中matplotlib绘图设置坐标轴刻度、文本
2018/02/07 Python
利用python求积分的实例
2019/07/03 Python
python读写Excel表格的实例代码(简单实用)
2019/12/19 Python
pandas分组聚合详解
2020/04/10 Python
selenium携带cookies模拟登陆CSDN的实现
2021/01/19 Python
购买瑞典当代设计的腕表和太阳眼镜:TRIWA
2016/10/30 全球购物
ORACLE第二个十问
2013/12/14 面试题
C#如何判断当前用户是否输入某个域
2015/12/07 面试题
知识竞赛活动方案
2014/02/18 职场文书
2014年卫生保健工作总结
2014/12/08 职场文书
生活小常识广播稿
2015/08/19 职场文书
七个非常实用的Python工具包总结
2021/06/15 Python
Python中glob库实现文件名的匹配
2021/06/18 Python
Java并发编程之详解CyclicBarrier线程同步
2021/06/23 Java/Android