原理很简单: 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년 1월 22일에 업데이트됨
jQuery API에서 hover 이벤트에 대한 설명을 확인했습니다.
에는 마우스가 여전히 특정 위치에 있는지 감지하는 기능이 포함됩니다. 요소(예: div의 이미지)가 있는 경우 move-out 이벤트를 트리거하지 않고 "hover" 상태를 계속 유지합니다(mouseout 이벤트 사용 시 흔히 발생하는 실수 수정).
마우스아웃에 버그가 있나요? 이는 제가 마우스로 작동되는 디스플레이 명함(Tencent Weibo의 아바타 명함과 유사) 작업을 할 때 마우스아웃 이벤트가 잘못 실행되는 경우가 많았던 것을 생각나게 합니다. 그래서 jQuery의 hover 소스 코드가 이 문제를 어떻게 해결하는지 확인했고, "mouseover"와 "mouseout" 대신 "mouseenter"와 "mouseleave"를 사용한다는 것을 발견했습니다(6, 7, 8). 고유 이벤트는 표준 브라우저에서 지원되지 않으며 시뮬레이션이 필요합니다. 최종 버전:
/*!
* hoverDelay.js v1.1
* http://www.planeArt.cn
* Copyright 2011, TangBin
* 듀얼 라이센스 MIT 또는 GPL 버전 2 라이선스
*/
(function (pluginName) {
var id = 0, data = {},
addEvent = function(elem, type, callback) {
if (elem.addEventListener) {
if (type === 'mouseenter') {
elem.addEventListener('mouseover', insideElement(callback), false)
} else if (type = == 'museleave') {
elem.addEventListener('mouseout', insideElement(callback), false)
} else {
elem.addEventListener(type, callback, false)
} ;
} else {
elem.attachEvent('on' type, function () {callback.call(elem, window.event)})
},
insideElement = function(callback) {
return 함수(이벤트) {
var parent = event.관련Target;
try {
while (parent && parent !== this) parent = parent.parentNode;
if (부모 !== this) callback.apply(this, 인수);
} catch(e) {}
}
this[pluginName] = 함수 ( elem, over, out, group, speed) {
id ;
if (arguments.length === 0) return id
if (typeofargs[1] !== 'function') returnclearTimeout(data[arguments[1]]);
if (typeof elem === 'string') elem = document.getElementById(elem);
group = group || ;
속도 = 속도 || 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.jb51.net/js/2011/hover/index.htm
새창열림
다운로드1,
네이티브버전 1.1
2.
jQuery 플러그인 버전