鼠标事件延时切换插件


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 相关文章推荐
js 屏蔽鼠标右键脚本附破解方法
Dec 03 Javascript
jQuery中获取Radio元素值的方法
Jul 02 Javascript
页面载入结束自动调用js函数示例
Sep 23 Javascript
ECMAScript中函数function类型
Jun 03 Javascript
jQuery拖拽排序插件制作拖拽排序效果(附源码下载)
Feb 23 Javascript
Ext JS框架中日期函数的用法及日期选择控件的实现
May 21 Javascript
浅谈vue 单文件探索
Sep 05 Javascript
JQueryDOM之样式操作
Mar 27 jQuery
基于Vue中使用节流Lodash throttle详解
Oct 30 Javascript
详解如何在JS代码中消灭for循环
Dec 11 Javascript
在vue中实现echarts随窗体变化
Jul 27 Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
Nov 09 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实现mysql数据库操作类分享
2014/02/14 PHP
ThinkPHP5.1表单令牌Token失效问题的解决
2019/03/22 PHP
js 关键词高亮(根据ID/tag高亮关键字)案例介绍
2013/01/21 Javascript
js实现从中间开始往上下展开网页窗口的方法
2015/03/02 Javascript
jquery实现平滑的二级下拉菜单效果
2015/08/26 Javascript
ionic隐藏tabs的方法
2016/08/29 Javascript
Angular学习笔记之angular的$filter服务浅析
2016/11/12 Javascript
jQuery 插件封装的方法
2016/11/16 Javascript
jquery插件treegrid树状表格的使用方法详解(.Net平台)
2017/01/03 Javascript
JavaScript中双向数据绑定详解
2017/05/03 Javascript
JS简单生成随机数(随机密码)的方法
2017/05/11 Javascript
mac上node.js环境的安装测试
2017/07/03 Javascript
jQuery实现的简单获取索引功能示例
2018/06/04 jQuery
微信小程序实现两个页面传值的方法分析
2018/12/11 Javascript
element-ui带输入建议的input框踩坑(输入建议空白以及会闪出上一次的输入建议问题)
2019/01/15 Javascript
使用Angular9和TypeScript开发RPG游戏的方法
2020/03/25 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
构建一个JavaScript插件系统
2020/10/20 Javascript
Vue3 实现双盒子定位Overlay的示例
2020/12/22 Vue.js
Vue实现圆环进度条的示例
2021/02/06 Vue.js
Python控制多进程与多线程并发数总结
2016/10/26 Python
python 每天如何定时启动爬虫任务(实现方法分享)
2018/05/21 Python
python try 异常处理(史上最全)
2019/03/07 Python
Django框架使用mysql视图操作示例
2019/05/15 Python
Python实现实时数据采集新型冠状病毒数据实例
2020/02/04 Python
python pandas利用fillna方法实现部分自动填充功能
2020/03/16 Python
PyQt5 如何让界面和逻辑分离的方法
2020/03/24 Python
CSS3 transition 实现通知消息轮播条
2020/10/14 HTML / CSS
CSS3只让背景图片旋转180度的实现示例
2021/03/09 HTML / CSS
表彰先进的通报
2014/01/31 职场文书
四风自我剖析材料思想汇报
2014/10/01 职场文书
小学老师对学生的评语
2014/12/29 职场文书
护士医德考评自我评价
2015/03/03 职场文书
学习焦裕禄观后感
2015/06/09 职场文书
2016春节放假通知范文
2015/08/18 职场文书
小学家庭教育心得体会
2016/01/14 职场文书