近期项目中需要写一个特效,根据鼠标在当前元素中的位置,利用 mousemove
事件使鼠标在图片左右时改变样式。引出几个问题:offsetX
兼容,target
和 currentTarget
,事件冒泡。
# 关于 offsetX
兼容
offsetX
: 发生事件的地点在事件源元素的坐标系统中的 x 坐标. 因为 FF 不兼容这个属性,所以我们只得曲线救国了。具体实现代码如下:
// 针对火狐不支持 offsetX/Y
function getOffset (e) {
var target = e.target, // 当前触发的目标对象
eventCoord,
pageCoord,
offsetCoord;
// 计算当前触发元素到文档的距离
pageCoord = getPageCoord(target);
// 计算光标到文档的距离
eventCoord = {
X: window.pageXOffset + e.clientX,
Y: window.pageYOffset + e.clientY
};
// 相减获取光标到第一个定位的父元素的坐标
offsetCoord = {
X: eventCoord.X - pageCoord.X,
Y: eventCoord.Y - pageCoord.Y
};
return offsetCoord;
}
function getPageCoord (element) {
var coord = { X : 0, Y : 0 };
// 计算从当前触发元素到根节点为止,
// 各级 offsetParent 元素的 offsetLeft 或 offsetTop 值之和
while (element) {
coord.X += element.offsetLeft;
coord.Y += element.offsetTop;
element = element.offsetParent;
}
return coord;
}
# target 和 currentTarget
target
: 返回触发事件的元素currentTarget
: 返回其事件监听器触发该事件的元素
所以我们可以通过比较 event.target
与 this
来确定事件是不是由于冒泡而触发的。
# 关于事件冒泡
我用一个 div
包住 img
, 然后在 div
上触发 mousemove
事件,当鼠标移至 img
上时 event.target
指向 img
, 也就是说 div
的子元素同样触发了 mousemove
事件(PS:这和不久前碰到的 IE 下子元素触发 mouseover
, mouseout
事件如出一辙。当时的解决方案是改用 mouseenter
, mouseleave
或者 setTimeout
, clearTimeout
控制)。回到 mousemove
, 来看看我的解决方案:
$('.wrap_1').mousemove(function (evt) {
var me = $(this),
// 根据触发事件元素调整 width
width = $(evt.target).width(),
posX = (evt.offsetX == undefined) ? getOffset(evt).offsetX : evt.offsetX;
if ( posX < width/2 ) {
me.removeClass("imgNext");
me.addClass("imgPrev");
} else {
me.removeClass("imgPrev");
me.addClass("imgNext");
}
});