鼠标事件延时切换插件


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 异步调用框架 (Part 1 - 问题 & 场景)
Aug 03 Javascript
Javascript 面向对象 继承
May 13 Javascript
javascript学习笔记(九) js对象 设计模式
Jun 19 Javascript
JS如何将UTC格式时间转本地格式
Sep 04 Javascript
JavaScript避免代码的重复执行经验技巧分享
Apr 17 Javascript
JavaScript的作用域和块级作用域概念理解
Sep 21 Javascript
浅谈javascript基础之客户端事件驱动
Jun 10 Javascript
jQuery编写网页版2048小游戏
Jan 06 Javascript
jquery ajaxfileupload异步上传插件使用详解
Feb 08 Javascript
Vue的实例、生命周期与Vue脚手架(vue-cli)实例详解
Dec 27 Javascript
使用vue实现grid-layout功能实例代码
Jan 05 Javascript
写gulp遇到的ES6问题详解
Dec 03 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令牌 Token改进版
2008/07/18 PHP
php数组函数序列之array_intersect() 返回两个或多个数组的交集数组
2011/11/10 PHP
PHP中new static()与new self()的区别异同分析
2014/08/22 PHP
php计划任务之验证是否有多个进程调用同一个job的方法
2015/12/07 PHP
php 如何禁用eval() 函数实例详解
2016/12/01 PHP
windows环境下使用Composer安装ThinkPHP5
2018/05/18 PHP
去除链接虚线全面分析总结
2006/08/15 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
AngularJS  ng-table插件设置排序
2016/09/21 Javascript
JS闭包与延迟求值用法示例
2016/12/22 Javascript
javascript十六进制数字和ASCII字符之间的转换方法
2016/12/27 Javascript
jQuery中DOM节点的删除方法总结(超全面)
2017/01/22 Javascript
js中document.referrer实现移动端返回上一页
2017/02/22 Javascript
微信小程序日历组件calendar详解及实例
2017/06/08 Javascript
vue 实现axios拦截、页面跳转和token 验证
2018/07/17 Javascript
Vue Router去掉url中默认的锚点#
2018/08/01 Javascript
js的新生代垃圾回收知识点总结
2019/08/22 Javascript
让IDE识别webpack的别名alias的实现方法
2020/05/06 Javascript
jquery实现有过渡效果的tab切换
2020/07/17 jQuery
浅谈javascript事件环微任务和宏任务队列原理
2020/09/12 Javascript
vue实现顶部菜单栏
2020/11/08 Javascript
一起深入理解js中的事件对象
2021/02/06 Javascript
[18:16]sakonoko 2017年卡尔集锦
2018/02/06 DOTA
Python基本数据类型详细介绍
2014/03/11 Python
python通过pil为png图片填充上背景颜色的方法
2015/03/17 Python
python读取并定位excel数据坐标系详解
2019/06/26 Python
Python学习之路安装pycharm的教程详解
2020/06/17 Python
用CSS3实现背景渐变的方法
2015/07/14 HTML / CSS
用C#语言写出在本地创建一个UDP接收端口的具体过程
2016/02/22 面试题
房地产还款计划书
2014/01/10 职场文书
七年级地理教学反思
2014/01/26 职场文书
电气自动化个人求职信范文
2014/02/03 职场文书
端午节将至,用Python爬取粽子数据并可视化,看看网友喜欢哪种粽子吧!
2021/06/11 Python
解析Java中的static关键字
2021/06/14 Java/Android
教你使用Jenkins集成Harbor自动发布镜像
2022/04/03 Servers
Redis基本数据类型Zset有序集合常用操作
2022/06/01 Redis