以前写过一个jQuery的图片放大效果,但是存在着一些小问题,然后最近有时间重写了一遍,做了很详尽的改进.改进了大部分bug,而且不采用jQuery.
该效果用于许多大型的购衣网站,用来方便别人浏览衣服的细节,实现了放大效果,可以放大图片进行浏览.只要鼠标放到图片上面,就会自动对其进行放大,还可以自行设置比例.十分方便.并且在IE6下利用iframe可以覆盖select,而且支持更重浏览器.在CSS设置上尚有欠缺,所以风转的不太好.还有代码写的比较乱,希望有什么意见的可以提出,然后我进行改正.
select测试
是否能覆盖
[程序说明] 主要为magnifier类,里面的主要方法有: init:运行方法 start:则是鼠标移入div的事件处理 move:则是鼠标在div中移动的事件处理 end:鼠标移出后的事件处理
[程序介绍] 主要思维:当鼠标移入图片的时候,放大层的DIV出现,然后根据鼠标移动状况,改变放大层内图像的top值和left值.使得2个地方保持一致的现实.而2个图像跟据比例进行设置,width和height值,使之产生放大的效果.下面进行详细的解释:
在init方法中,主要处理浏览框div层的大小,放大框的大小和放大的图像大小. 浏览框div的width和height跟据,原始图片的大小/比例值可以获得,见代码:
css(m.cont.getElementsByTagName( ' div ' )[ 0 ],{ // m.cont.getElementsByTagName('div')[0]为浏览框
' display ' : ' none ' , // 开始设置为不可见
' width ' : m.cont.clientWidth / m.scale - borderWid + ' px ' , // 原始图片的宽/比例值 - border的宽度
' height ' : m.cont.clientHeight / m.scale - borderWid + ' px ' , // //原始图片的高/比例值 - border的宽度
' opacity ' : 0.5 // 设置透明度
})
放大框的大小则设置为于原始图像相同大小,代码如下:
css(m.mag,{
' display ' : ' none ' ,
' width ' : m.cont.clientWidth + ' px ' , // m.cont为原始图像
' height ' : m.cont.clientHeight + ' px ' ,
' position ' : ' absolute ' ,
' left ' : m.cont.offsetLeft + m.cont.offsetWidth + 10 + ' px ' , // 放大框的位置为原始图像的右方远10px
' top ' : m.cont.offsetTop + ' px '
})
放大的图像大小为,原始图像大小*比例值,代码如下:
css(m.img,{
' position ' : ' absolute ' ,
' width ' : (m.cont.clientWidth * m.scale) + ' px ' , // 原始图像的宽*比例值
' height ' : (m.cont.clientHeight * m.scale) + ' px ' // 原始图像的高*比例值
})
由于放大是根据比例进行放大,所以在浏览框上和放大图像上需要仔细计算,这也就是该程序的主要思维之一.
在第一次写的程序里,直接省去了onmouseover,因为直接使用onmousemove就可以满足功能.而这次使用onmouseover是为了避免在使用过程中遇到select,在IE6下,select无法设置z-Index值,使得放大框的突然出现却无法覆盖select.详细下面在讨论.
在move方法中,最重要的就是如果做到鼠标移动过程中,浏览框随着鼠标移动的同时,放大图像也跟着运动,使得放大图像所显示的范围与浏览框所在原始图像位置一致 . 先说说浏览框跟随鼠标移动,主要代码如下:
top:pos.y - this .offsetTop - parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.height) / 2
left:pos.x - this .offsetLeft - parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.width) / 2
由于是,对m.cont绑定事件,所以这个时候this指向m.cont. 由图像可以得知left=鼠标x - this.offsetLeft - 浏览框宽/2,所以跟据该几何思想可以得出而代码,而top的值也是根据一样的道理所得,这里就不做详细解释了. 接下来就是在鼠标运动的同时,放大图像也要跟着改变top和left值,代码如下:
css(magnifier.m.img,{
' top ' : - (parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.top) * magnifier.m.scale) + ' px ' ,
' left ' : - (parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.left) * magnifier.m.scale) + ' px '
})
代码很清晰的可以得出,只需要在浏览框的top和left值上*比例就可以了.而加上负号的原因是默认坐标为(0,0),而在移动过程中,始坐标只会向负方向移动. 在该方法中有2个需要注意的地方: 1.
this .getElementsByTagName( ' div ' )[ 0 ].style.display = '' ;
应该放在设置this.getElementsByTagName('div')[0]的top与left之前,原因是如果display为none的话,无法获取其宽和高.如果把display = ''放在设置top与left之后,会出现一个奇怪的现象,大家可以试下,该问题一直困扰了我很久,在多次尝试中才发现问题再这上面,现象如下:
2.
' top ' : Math.min(Math.max(pos.y - this .offsetTop - parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.height) / 2 , 0 ), this .clientHeight - this .getElementsByTagName( ' div ' )[ 0 ].offsetHeight) + ' px ' ;
这么长的代码可能让人很困惑,我只是用Math.max()和Math.min()去避免了采用if语句,自己偷了点懒,就是为了实现浏览框不会超出原始图像而已,仔细看看就清楚啦.^^
end方法很清晰,就是浏览框和放大框进行隐藏.
[覆盖select] 在为了在IE6下可以覆盖select,我加入了2个放法createIframe和removeIframe.分别是在onmouseover事件里创建一个iframe和在onmouseout里销毁iframe.
createIframe: function (elem){
var layer = document.createElement( ' iframe ' );
layer.tabIndex = ' -1 ' ;
layer.src = ' javascript:false; ' ;
elem.parentNode.appendChild(layer);
layer.style.width = elem.offsetWidth + ' px ' ;
layer.style.height = elem.offsetHeight + ' px ' ;
}
首先需要使用负的tabIndex值把iframe排除在tab序列之外,否则用户可能会使用键盘导航到它,这就乱了套了,所以需要将tabIndex值设置为负的.另外,还要设置src,设置该值是为了避免在SSL页面上出现问题.在IE中,没有设置src的iframe将会自动装载about:blank.IE将此视为不安全页面,而且会产生一个警告对话框,内容是"该页面包含安全和非安全的内容".为了避免这个问题,可以将src设置为"javascript:false;".(该段摘自<<JavaScript精髓>>) 而避免iframe在页面所造成的混乱,所以在onmouseout中将iframe销毁,而不对其进行隐藏.
[使用说明] 由于时间上的问题,所以没有封装的太好,主要是在CSS上,最好根据我所设置的那样设置,感觉有些乱.希望大家能够理解,而修改也不会太难.因为我自带一个css()函数,只要稍加设置就可以了.使用例子:
magnifier.init({
cont : document.getElementById( ' magnifier ' ),
img : document.getElementById( ' magnifierImg ' ),
mag : document.getElementById( ' mag ' ),
scale : 3
});
cont为container缩写,指的是装载原始图像的div img则是放大的图像 mag则为magnifier缩写,是指放大框 scale为比例值,设置的值越大放大越大,但是这里有个问题就是如果不可以整除时,会产生些很小的白边,目前不知道如何解决 至于浏览框和原始图像为m.cont.getElementsByTagName('img')[0]和m.cont.getElementsByTagName('div')[0],所以建议在装载图像的div中最好只放一个div和img.
[程序代码]
Code
function getEventObject(W3CEvent) { // 事件标准化函数
return W3CEvent || window.event;
}
function getPointerPosition(e) { // 兼容浏览器的鼠标x,y获得函数
e = e || getEventObject(e);
var x = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
var y = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
return { ' x ' :x, ' y ' :y };
}
function setOpacity(elem,level) { // 兼容浏览器设置透明值
if (elem.filters) {
elem.style.filter = ' alpha(opacity= ' + level * 100 + ' ) ' ;
} else {
elem.style.opacity = level;
}
}
function css(elem,prop) { // css设置函数,可以方便设置css值,并且兼容设置透明值
for ( var i in prop) {
if (i == ' opacity ' ) {
setOpacity(elem,prop[i]);
} else {
elem.style[i] = prop[i];
}
}
return elem;
}
var magnifier = {
m : null ,
init: function (magni){
var m = this .m = magni || {
cont : null , // 装载原始图像的div
img : null , // 放大的图像
mag : null , // 放大框
scale : 15 // 比例值,设置的值越大放大越大,但是这里有个问题就是如果不可以整除时,会产生些很小的白边,目前不知道如何解决
}
css(m.img,{
' position ' : ' absolute ' ,
' width ' : (m.cont.clientWidth * m.scale) + ' px ' , // 原始图像的宽*比例值
' height ' : (m.cont.clientHeight * m.scale) + ' px ' // 原始图像的高*比例值
})
css(m.mag,{
' display ' : ' none ' ,
' width ' : m.cont.clientWidth + ' px ' , // m.cont为原始图像,与原始图像等宽
' height ' : m.cont.clientHeight + ' px ' ,
' position ' : ' absolute ' ,
' left ' : m.cont.offsetLeft + m.cont.offsetWidth + 10 + ' px ' , // 放大框的位置为原始图像的右方远10px
' top ' : m.cont.offsetTop + ' px '
})
var borderWid = m.cont.getElementsByTagName( ' div ' )[ 0 ].offsetWidth - m.cont.getElementsByTagName( ' div ' )[ 0 ].clientWidth; // 获取border的宽
css(m.cont.getElementsByTagName( ' div ' )[ 0 ],{ // m.cont.getElementsByTagName('div')[0]为浏览框
' display ' : ' none ' , // 开始设置为不可见
' width ' : m.cont.clientWidth / m.scale - borderWid + ' px ' , // 原始图片的宽/比例值 - border的宽度
' height ' : m.cont.clientHeight / m.scale - borderWid + ' px ' , // 原始图片的高/比例值 - border的宽度
' opacity ' : 0.5 // 设置透明度
})
m.img.src = m.cont.getElementsByTagName( ' img ' )[ 0 ].src; // 让原始图像的src值给予放大图像
m.cont.style.cursor = ' crosshair ' ;
m.cont.onmouseover = magnifier.start;
},
start: function (e){
if (document.all){ // 只在IE下执行,主要避免IE6的select无法覆盖
magnifier.createIframe(magnifier.m.img);
}
this .onmousemove = magnifier.move; // this指向m.cont
this .onmouseout = magnifier.end;
},
move: function (e){
var pos = getPointerPosition(e); // 事件标准化
this .getElementsByTagName( ' div ' )[ 0 ].style.display = '' ;
css( this .getElementsByTagName( ' div ' )[ 0 ],{
' top ' : Math.min(Math.max(pos.y - this .offsetTop - parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.height) / 2 , 0 ), this .clientHeight - this .getElementsByTagName( ' div ' )[ 0 ].offsetHeight) + ' px ' ,
' left ' : Math.min(Math.max(pos.x - this .offsetLeft - parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.width) / 2 , 0 ), this .clientWidth - this .getElementsByTagName( ' div ' )[ 0 ].offsetWidth) + ' px ' // left=鼠标x - this.offsetLeft - 浏览框宽/2,Math.max和Math.min让浏览框不会超出图像
})
magnifier.m.mag.style.display = '' ;
css(magnifier.m.img,{
' top ' : - (parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.top) * magnifier.m.scale) + ' px ' ,
' left ' : - (parseInt( this .getElementsByTagName( ' div ' )[ 0 ].style.left) * magnifier.m.scale) + ' px '
})
},
end:function (e){
this .getElementsByTagName( ' div ' )[ 0 ].style.display = ' none ' ;
magnifier.removeIframe(magnifier.m.img); // 销毁iframe
magnifier.m.mag.style.display = ' none ' ;
},
createIframe: function (elem){
var layer = document.createElement( ' iframe ' );
layer.tabIndex = ' -1 ' ;
layer.src = ' javascript:false; ' ;
elem.parentNode.appendChild(layer);
layer.style.width = elem.offsetWidth + ' px ' ;
layer.style.height = elem.offsetHeight + ' px ' ;
},
removeIframe: function (elem){
var layers = elem.parentNode.getElementsByTagName( ' iframe ' );
while (layers.length > 0 ){
layers[ 0 ].parentNode.removeChild(layers[ 0 ]);
}
}
}
完整程序下载