淘宝首页装饰宝贝图片时鼠标变大了怎么办?
一般用于放大查看商品图片,在JD.COM商城、柯凡、阿里巴巴都有类似的效果。
好处是可以在原图附近局部放大查看图片,可以用鼠标控制查看位置。
基本原理
首先,必须有一个img元素作为原始对象,一个容器作为显示框。
在显示框中再放一个img元素作为大图对象,根据比例设置大小。
当鼠标在原图上移动时,通过大图的绝对定位来显示相应的部分,实现了类似放大镜的效果。
图片加载
程序初始化时会先执行_initLoad程序,主要用来加载图片。
因为加载前img得到的尺寸不准确,所以相关参数的计算要等到图片加载后。
放大有两种方式:用原图像放大,用放大后的新图像。
放大原图的好处是只需要加载一张图片,使用新的图片可以获得更清晰的效果。
根据不同的方法,会选择相应的原始加载器:
useOrigin =!这个。_ zoomPic & amp& amp这个。_scale,
loadImage = $$F.bind( useOrigin?这个。_loadOriginImage:这个。_loadImage,this);
当未设置大图像但有放大倍率时,将自动使用原始图像放大加载器。
我们来看看用原图放大加载的过程:
1,加载原图:
if(origin pic & amp;& amporiginPic!= image.src ) {
image.onload = loadImage
image.src = originPic
} else if ( image.src ) {
如果(!image.complete ) {
image.onload = loadImage
}否则{
loadImage();
}
}否则{
返回;
}
_originPic属性记录原始图像的地址。如果原始图像已设置,并且不同于元素的当前加载图像,则设置onload并加载原始图像。
否则,如果该元素当前有加载的图片,先通过complete判断加载是否完成,设置onload不停止。如果完成,直接执行加载程序。
最后,如果没有原图,退出程序。
2.执行_loadOriginImage加载程序:
这个。_ image.onload = null
这个。_zoom.src = this。_ image.src
这个。_ init loaded();
因为ie6/7的gif图片加载有bug,所以会先重置onload。
然后execute _initLoaded初始化负载设置程序。
使用新图片有点复杂:
1,加载原图,如上。
2.预装大图:
var preload = this。_preload,zoomPic = this。_zoomPic || image.src,
loadPreload = $$F.bind( this。_loadPreload,this);
如果(zoomPic!= preload.src ) {
preload.onload = loadPreload
preload.src = zoomPic
}否则{
如果(!preload.complete ) {
preload.onload = loadPreload
}否则{
这个。_ load preload();
}
}
_preload是一个预加载对象,使用_loadPreload预加载器。
预装对象主要是用来获取大图的原始尺寸,也是后面原图替换技能的基础。
如果没有大图,说明目前没有大图,没有放大,所以用原图做大图。
加载方式和原图差不多。
3.加载原始图像后,执行_loadImage原始图像加载程序:
复制代码
如果(这个。_loaded ) {
这个。_ init loaded();
}否则{
这个。_ loaded = true
如果(这个。_scale ) {
这个。_ substitute = true
这个。_zoom.src = this。_ image.src
这个。_ init loaded();
}
}
复制代码
如果_loaded为真,说明已经加载了大图,直接执行_initLoaded程序。
否则,将_loaded设置为true,以标记原始图像已经加载。如果此时有自定义比例,先用原图替换大图。
因为大图加载通常比较慢,所以可以通过先替换原图来立即操作,将_substitute属性设置为true标志使用替换。
4.完成大图预加载后,执行_loadPreload大图预加载程序:
这个。_zoom.src = this。_ preload.src
如果(这个。_loaded ) {
如果(!这个。_substitute ) {这个。_ init loaded();}
}否则{
这个。_ loaded = true
}
如果_loaded为true,则表示原映像已经加载,如果_substitute为false,即原映像没有被替换,则执行_initLoaded程序。
如果原始图像没有完全加载,将_loaded设置为true以标记大图像已经加载。
关于图像加载的另一个问题,测试下面的代码:
复制代码
& lt脚本& gt
var img =新图像
功能测试(){
img . onload = function(){ alert(" load ")}
img.src= "。hk/images/nav_logo8.png "
}
测试()
设置超时(测试,3000)
& lt/script & gt;
复制代码
在chrome/safari中,“加载”只会弹出一次,其他都正常两次,可能是优化了什么的。
加载完成后,可以设置相关的对象和参数,这些都在_initLoaded程序中进行。
负载设置
初始化加载设置程序in _initLoaded,主要是为触发放大效果做准备。
步骤1,执行_initSize程序初始化显示尺寸。
首先,校正放大比例:
如果(!scale ) { scale =这个。_ preload . width/image . width;}
这个。_ scale = scale = math . min(math . max(this。_min,scale),这个。_ max);
如果未设置比例,则从预加载的对象中获得的默认尺寸将作为大图形尺寸。
加载图片时采取了“安全措施”,以确保在此处可以获得放大倍率。
您还可以通过自定义最大值和最小值属性来限制比例大小。
然后你可以按比例设置大图的大小:
zoom . width = math . ceil(image . width * scale);
zoom . height = math . ceil(image . height * scale);
第二步,执行_initViewer初始化显示框程序,设置显示框。
首先设置样式:
var styles = { padding: 0,overflow: "hidden" },p = $$D.getStyle( viewer," position ");
如果(p!= "亲戚" & amp& ampp!= " absolute "){ styles . position = " relative ";};
$$D.setStyle(查看器,样式);
zoom . style . position = " absolute ";
然后将显示图插入显示框:
如果(!$$D.contains( viewer,zoom)){ viewer . appendchild(zoom);}
第三步是执行_initData初始化数据程序,主要是设置一些放大时使用的参数。
包括用于位置判断的原始坐标:
这个。_ rect = $ $ d . rect(image);
左侧/顶部校正的校正参数:
这个。_ repair left = image . client left+parse int($ $ d . get style(image," padding-left "));
这个。_ repair top = image . client top+parse int($ $ d . get style(image," padding-top));
还有范围参数和显示大小。
range参数是原始图像中要显示的范围的大小,display size是显示帧的显示大小。
如果范围参数由rangeWidth和rangeHeight定制,则可以通过组合放大比率来计算显示尺寸:
range width = math . ceil(range width);
range height = math . ceil(range height);
这个。_ viewer width = math . ceil(range width * scale);
这个。_ viewer height = math . ceil(range height * scale);
$$D.setStyle(查看器,{
宽度:这个。_viewerWidth + "px ",
身高:这个。_viewerHeight + "px "
});
复制代码
如果未设置,将使用显示框的默认显示大小:
复制代码
var风格;
如果(!viewer.clientWidth ) {
var style = viewer.style
样式= {
显示:style.display,
位置:style.position,
可视性:样式.可视性
};
$$D.setStyle(查看器,{
显示:“阻挡”,位置:“绝对”,可见性:“隐藏”
});
}
这个。_ viewer width = viewer . client width;
这个。_ viewer height = viewer . client height;
if ( styles ) { $$D.setStyle(查看器,样式);}
rangeWidth = Math.ceil( this。_ viewer width/scale);
rangeHeight = Math.ceil( this。_ viewer height/scale);
复制代码
注意,显示范围是通过clientWidth/clientHeight获得的。
如果显示框处于隐藏状态,显示为none,则不能直接获取clientWidth/clientHeight。
在这种情况下,程序使用以下方法来获取:
1,记录显示/位置/可见度的原始值;
2,分别设置为“块”/“绝对”/“隐藏”,可以隐藏也可以占用;
3、获取参数;
4、复位原值,恢复原始状态。
得到显示范围后,匹配比例就可以得到范围参数。
Ps:这是一种通用的获取非占用元素大小参数的方法,jquery的css也使用这种方法获取宽度/高度。
按比例计算后,可能会得到小数,但大小只能是整数,程序总是用Math.ceil来取整。
放大效应
设置好一切后,您可以执行开始设置触发器。
程序会自动执行start方法,主要是将_start程序绑定到原始图像对象的mouseover/mousemove上:
var image = this。_image,START = this。_ START
$$E.addEvent( image," mouseover ",START);
$$E.addEvent( image," mousemove ",START);
对应于移入原始对象和在原始对象上移动的情况。
Ps:如果使用attachEvent,还要注意同一个函数重复绑定的问题。这里的addEvent没有这个问题。
bound _start程序主要用于解除绑定和绑定一些事件:
密码
为了在移出窗口时结束放大效果,将_OUT程序绑定到mouseout of document:
这个。_OUT = $$F.bindAsEventListener(函数(e){
如果(!e.relatedTarget)这个。_ END();
},这个);
当鼠标移出文档时,会触发mouseout。如果当前relatedTarget为空,将延迟执行_end来结束程序:
var oThis = this,END = function(){ oThis。_ end();};
这个。_END = function(){ oThis。_timer = setTimeout( END,othis . delay);};
在_end程序中,将首先执行stop方法来删除所有可能的绑定事件,然后执行start方法来继续等待触发器。
mousemove绑定的_move移动程序主要用于鼠标移动到哪里就放大到哪里。
为了适应更多的情况(比如扩展的其他模式),它被绑定到文档,但因此mouseout事件不能用来触发移除程序。
程序比较鼠标和原始图像的坐标,判断鼠标是否移出原始图像对象范围:
var x = e.pageX,y = e.pageY,rect = this。_ rect
if(x & lt;rect.left | | x & gtrect.right | | y & ltrect.top | | y & gtrect.bottom ) {
这个。_ END();
}否则{
...
}
如果鼠标移出原图像对象,执行_END结束放大效果。
如果鼠标在原始对象上移动,将计算坐标以进行定位。
首先修正坐标,将鼠标坐标转换成大图的定位坐标:
pos . left = viewer width/2-(x-rect . left-this。_ repair left)* scale;
pos . top = viewer height/2-(y-rect . top-this。_repairTop ) *比例;
再次设置范围限制:
x = math . ceil(math . min(math . max(pos . left,viewerWidth - zoom.width),0));
y = math . ceil(math . min(math . max(pos . top,viewerHeight - zoom.height),0));
最后,设置定位,使显示框显示要放大的部分。
Ps:我尝试过用scrollLeft/scrollTop定位,但是发现在ie里会像锯齿一样移动,而且越大越明显,所以放弃了。
鼠标滚动和缩放
如果mouse属性设置为true,将打开鼠标滚动和缩放功能。
在放大效果期间,您可以通过滚动鼠标滚轮来放大大图。
其实就是根据压路机动力学参数的变化来修改放大倍数。
关于鼠标滚动事件,slider里也有提到,但当时只分析了ie和ff的区别。这里再来分析一下。
首先,ie使用mousewheel绑定事件,使用事件的wheelDelta获取滚动参数。
其他浏览器使用以下代码进行测试:
密码
向下滚动,可以得到以下结果:
ff:DOMMouseScroll:3_undefined
歌剧:鼠标滚轮:3_-120
chrome/safari:鼠标滚轮:0_-120
可以看到事件的绑定,ff只支持DOMMouseScroll,其他只支持mousewheel。
至于滚动参数的获取,ff只支持detail和opera,chrome/safari支持wheelDelta。
Ps:不明白为什么chrome/safari的细节是0,还有其他用途。
DOMMouseScroll和mousewheel的另一个区别是,前者不能直接绑定元素,而后者可以。
也就是说,你可以elem.onmousewheel,但是不能elem.onDOMMouseScroll。
根据以上分析,在_start程序中,_mouse程序与文档的滚动事件绑定如下:
这只老鼠& amp& amp$$E.addEvent(文档,$$B.firefox?" dommousscroll ":" mouse wheel ",这个。_ MOUSE);
在_mouse程序中,根据滚动参数和用户自定义的缩放比率获得新的缩放比率:
这个。_scale += ( e.wheelDelta?e . wheel delta/(-120):(e . detail | | 0)/3)* this . rate;
修改比例时,程序参数也需要重新计算。
由于_rangeWidth/_rangeHeight会影响计算过程,因此有必要恢复到用户定义的默认值:
var opt = this.options
这个。_ range width = opt . range width;
这个。_ range height = opt . range height;
然后执行_initSize和_initData重置大小和参数,然后执行_move重定位。
最后,记得使用preventDefault来防止触发页面滚动。