鼠标事件延时切换插件


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 相关文章推荐
再谈ie和firefox下的document.all属性
Oct 21 Javascript
jQuery解决iframe高度自适应代码
Dec 20 Javascript
javascript中检测变量的类型的代码
Dec 28 Javascript
从零开始学习jQuery (十) jQueryUI常用功能实战
Feb 23 Javascript
javascript实现倒计时(精确到秒)
Jun 26 Javascript
jQuery+PHP星级评分实现方法
Oct 02 Javascript
JS 实现导航菜单中的二级下拉菜单的几种方式
Oct 31 Javascript
vue 怎么创建组件及组件使用方法
Jul 27 Javascript
JS数组实现分类统计实例代码
Sep 30 Javascript
Vue监听滚动实现锚点定位(双向)示例
Nov 13 Javascript
手动实现vue2.0的双向数据绑定原理详解
Feb 06 Vue.js
Vue ECharts实现机舱座位选择展示功能
May 15 Vue.js
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
Mysql的常用命令
2006/10/09 PHP
一些常用的php函数
2006/12/06 PHP
mysql时区问题
2008/03/26 PHP
解析php mysql 事务处理回滚操作(附实例)
2013/08/05 PHP
php实现将任意进制数转换成10进制的方法
2015/04/17 PHP
PHP递归创建多级目录
2015/11/05 PHP
Laravel框架基于ajax实现二级联动功能示例
2019/01/17 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式一图文详解
2019/04/09 PHP
JavaScript中的prototype使用说明
2010/04/13 Javascript
jQuery中:last选择器用法实例
2014/12/30 Javascript
TinyMCE提交AjaxForm获取不到数据的解决方法
2015/03/05 Javascript
AngularJS学习笔记之ng-options指令
2015/06/16 Javascript
jquery实现鼠标悬浮停止轮播特效
2020/08/20 Javascript
Node.js模块封装及使用方法
2016/03/06 Javascript
js变量提升深入理解
2016/09/16 Javascript
jquery控制页面的展开和隐藏实现方法(推荐)
2016/10/15 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
jQuery Masonry瀑布流插件使用方法详解
2017/01/18 Javascript
vue实现计算器功能
2020/02/22 Javascript
Bootstrap实现前端登录页面带验证码功能完整示例
2020/03/26 Javascript
[57:55]EG vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python脚本实现xls(xlsx)转成csv
2016/04/10 Python
python logging重复记录日志问题的解决方法
2018/07/12 Python
python排序函数sort()与sorted()的区别
2018/09/18 Python
如何实现Django Rest framework版本控制
2019/07/25 Python
python的数学算法函数及公式用法
2020/11/18 Python
快速创建python 虚拟环境
2020/11/28 Python
Html5+CSS3+EL表达式问题小结
2020/12/19 HTML / CSS
娇韵诗加拿大官网:Clarins加拿大
2017/11/20 全球购物
奇怪的鱼:Weird Fish
2018/03/18 全球购物
Paul Smith英国官网:英国国宝级时装品牌
2019/03/21 全球购物
介绍一下Linux文件的记录形式
2012/04/18 面试题
会计系个人求职信范文分享
2013/12/20 职场文书
初三家长会邀请函
2014/01/18 职场文书
2016年基层党组织公开承诺书
2016/03/25 职场文书
Python使用Kubernetes API访问集群
2021/05/30 Python