鼠标事件延时切换插件


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 HTML中的table
Apr 15 Javascript
jquery用offset()方法获得元素的xy坐标
Sep 06 Javascript
学习JavaScript编程语言的8张思维导图分享
Mar 27 Javascript
JS中正则表达式只有3种匹配模式(没有单行模式)详解
Jul 28 Javascript
JavaScript编码风格指南(中文版)
Aug 26 Javascript
浅析bootstrap原理及优缺点
Mar 19 Javascript
JavaScript中如何判断一个值的类型
Sep 15 Javascript
js + css实现标签内容切换功能(实例讲解)
Oct 09 Javascript
Node.js静态服务器的实现方法
Feb 28 Javascript
微信小程序中this.data与this.setData的区别详解
Sep 17 Javascript
JavaScript使用Math.random()生成简单的验证码
Jan 21 Javascript
JS Canvas接口和动画效果大全
Apr 29 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函数)
2006/10/09 PHP
JS中encodeURIComponent函数用php解码的代码
2012/03/01 PHP
深入Nginx + PHP 缓存详解
2013/07/11 PHP
php使用curl发送json格式数据实例
2013/12/17 PHP
采用ThinkPHP中F方法实现快速缓存实例
2014/06/13 PHP
thinkphp使用phpmailer发送邮件的方法
2014/11/24 PHP
php识别翻转iphone拍摄的颠倒图片
2018/05/17 PHP
详解no input file specified 三种解决方法
2019/11/29 PHP
解读IE和firefox下JScript和HREF的执行顺序
2008/01/12 Javascript
ExtJS 2.0 实用简明教程之布局概述
2009/04/29 Javascript
javascript实现2016新年版日历
2016/01/25 Javascript
JavaScript模版引擎的基本实现方法浅析
2016/02/15 Javascript
jQuery Validate设置onkeyup验证的实例代码
2016/12/09 Javascript
微信小程序左右滑动切换页面详解及实例代码
2017/02/28 Javascript
js实现分页功能
2017/05/24 Javascript
nodejs连接mysql数据库及基本知识点详解
2018/03/20 NodeJs
使用JSON格式提交数据到服务端的实例代码
2018/04/01 Javascript
用Vue写一个分页器的示例代码
2018/04/22 Javascript
JavaScript面向对象的程序设计(犯迷糊的小羊)
2018/05/27 Javascript
layui中table表头样式修改方法
2018/08/15 Javascript
Vuejs监听vuex中值的变化的方法示例
2018/12/02 Javascript
Vue单文件组件开发实现过程详解
2020/07/30 Javascript
jQuery实现滑动开关效果
2020/08/02 jQuery
简单的编程0基础下Python入门指引
2015/04/01 Python
Python的Flask框架与数据库连接的教程
2015/04/20 Python
详解Python的数据库操作(pymysql)
2019/04/04 Python
python如何实现数据的线性拟合
2019/07/19 Python
html5实现多文件的上传示例代码
2014/02/13 HTML / CSS
基于Html5 canvas实现裁剪图片和马赛克功能及又拍云上传图片 功能
2019/07/09 HTML / CSS
欧缇丽英国官方网站:Caudalie英国
2016/08/17 全球购物
绩效工资分配方案
2014/01/18 职场文书
我为自己代言广告词
2014/03/18 职场文书
公司开业庆典主持词
2014/03/21 职场文书
求职信的正确写法
2014/07/10 职场文书
租房协议书范例
2014/10/14 职场文书
Python 读取千万级数据自动写入 MySQL 数据库
2022/06/28 Python