鼠标事件延时切换插件


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 相关文章推荐
ExtJS下grid的一些属性说明
Dec 13 Javascript
基于jquery的合并table相同单元格的插件(精简版)
Apr 05 Javascript
禁用键盘上的(全局)指定键兼容iE、Chrome、火狐
May 14 Javascript
js如何实现设计模式中的模板方法
Jul 23 Javascript
artDialog双击会关闭对话框的修改过程分享
Aug 05 Javascript
JavaScript用JQuery呼叫Server端方法示例代码
Sep 03 Javascript
JavaScript中操作字符串小结
May 04 Javascript
浅谈JavaScript事件绑定的常用方法及其优缺点分析
Nov 01 Javascript
JS实现点击Radio动态更新table数据
Jul 18 Javascript
jQuery动态添加.active 实现导航效果代码思路详解
Aug 29 jQuery
使用live-server快速搭建本地服务器+自动刷新的方法
Mar 09 Javascript
详解Vue3.0 + TypeScript + Vite初体验
Feb 22 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
php 前一天或后一天的日期
2008/06/28 PHP
PHP用户验证和标签推荐的简单使用
2016/10/31 PHP
CI框架无限级分类+递归的实现代码
2016/11/01 PHP
微信公众平台开发教程③ PHP实现微信公众号支付功能图文详解
2019/04/10 PHP
Ext对基本类型的扩展 ext,extjs,format
2010/12/25 Javascript
仅IE6/7/8中innerHTML返回值忽略英文空格的问题
2011/04/07 Javascript
纯Javascript实现Windows 8 Metro风格实现
2013/10/15 Javascript
jquery禁止输入数字以外的字符的示例(纯数字验证码)
2014/04/10 Javascript
AngularJS入门教程之Select(选择框)详解
2016/07/27 Javascript
老生常谈JQuery data方法的使用
2016/09/09 Javascript
详解Angular2 之 结构型指令
2017/06/21 Javascript
基于javaScript的this指向总结
2017/07/22 Javascript
pm2 部署 node的三种方法示例
2017/10/20 Javascript
微信小程序之自定义组件的实现代码(附源码)
2018/08/02 Javascript
对vux点击事件的优化详解
2018/08/28 Javascript
vue+node实现图片上传及预览的示例方法
2018/11/22 Javascript
vue用BMap百度地图实现即时搜索功能
2019/09/26 Javascript
vue实现循环滚动列表
2020/06/30 Javascript
Jquery cookie插件实现原理代码解析
2020/08/04 jQuery
python插入数据到列表的方法
2015/04/30 Python
python对常见数据类型的遍历解析
2019/08/27 Python
wxPython实现画图板
2020/08/27 Python
Anaconda3+tensorflow2.0.0+PyCharm安装与环境搭建(图文)
2020/02/18 Python
如何编写python的daemon程序
2021/01/07 Python
ProBikeKit英国:在线公路自行车之家
2017/02/10 全球购物
英国工艺品购物网站:Minerva Crafts
2018/01/29 全球购物
天游软件面试
2013/11/23 面试题
优秀学生自我鉴定范例
2013/12/18 职场文书
房地产开发计划书
2014/01/10 职场文书
大学生党员自我批评
2014/02/14 职场文书
教师一岗双责责任书
2014/04/16 职场文书
2014年学前班工作总结
2014/12/08 职场文书
我的中国梦主题教育活动总结
2015/05/07 职场文书
办公经费申请报告
2015/05/15 职场文书
水浒传读书笔记
2015/06/25 职场文书
Mysql使用全文索引(FullText index)的实例代码
2022/04/03 MySQL