本文实例为大家分享了js实现放大镜组件开发的具体代码,供大家参考,具体内容如下
功能需求:
1、根据图片数组创建图标列表;
2、鼠标滑过图标时,当前图标增加红色边框;
3、鼠标滑过图标时,上方图片区域显示对应的图片,右侧显示放大后的图片内容;
4、鼠标在图片区域移动时,在右侧实现放大效果;
5、下方图标列表,点击左右按钮,实现翻页效果;
6、当图标内容不够一页时,只移动到最后一个图标的位置;
以京东的详情页为例,看一下效果:
放大镜内容写在 Zoom.js 文件里,下方的图标列表内容写在 IconList.js 文件里,当鼠标滑过下面的图标时,需要更改放大镜里div的背景图片,这里用到了事件抛发。
下面附上代码:
html结构 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title >zoom</ title > </ head > < body > < script type = "module" > import Zoom from './js/Zoom.js'; //图标数组 let list=["a_icon.jpg","e_icon.jpg","f_icon.jpg","g_icon.jpg","h_icon.jpg","i_icon.jpg","j_icon.jpg",]; init(); function init(){ let zoom=new Zoom(list,"./img/"); zoom.appendTo("body"); } </ script > </ body > </ html > |
Zoom.js文件,创建放大镜组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import Utils from "./Utils.js" ; import IconList from './IconList.js' ; export default class Zoom{ static styles= false ; static small_width=450; static mask_width=303.75; static zoom_width=540; static SET_BG_IMG= "set_bg_img" ; constructor(_list,_basePath){ if (_basePath) _list=_list.map(item=>_basePath+item); //创建外层的div容器 this .elem= this .createE(); //监听事件,改变zoomSmall的背景图 document.addEventListener(Zoom.SET_BG_IMG,e=> this .setBgImg(e)); //创建下方的icon列表 this .createIconList(_list, this .elem); } createE(){ //创建外层div容器 let div=Utils.createE( "div" ); div.className= "zoomContainer" ; div.innerHTML=`<div class= "zoomSmall" id= "zoomSmall" ><div class= "zoomMask" id= "zoomMask" ></div></div> <div class= "zoomContent" id= "zoomCont" ></div>`; //设置样式 Zoom.setStyle(); //获取样式 Utils.getIdElem(div, this ); //监听鼠标滑入事件 this .zoomSmall.addEventListener( "mouseenter" ,e=> this .mouseHandler(e)); return div; } appendTo(parent){ Utils.appendTo( this .elem,parent); } setBgImg(e){ //设置背景图片 this .zoomSmall.style.backgroundImage=`url(${e.src})`; this .zoomCont.style.backgroundImage=`url(${e.src})`; } createIconList(list,parent){ //创建下方icon图标列表 let iconList= new IconList(list); Utils.appendTo(iconList.elem,parent); } mouseHandler(e){ switch (e.type) { case "mouseenter" : //鼠标滑入后,显示遮罩和右侧大图片 this .zoomMask.style.display= "block" ; this .zoomCont.style.display= "block" ; //监听鼠标移动和滑出事件 this .mouseHandlers=e=> this .mouseHandler(e); this .zoomSmall.addEventListener( "mousemove" , this .mouseHandlers); this .zoomSmall.addEventListener( "mouseleave" , this .mouseHandlers); break ; case "mousemove" : //遮罩移动 this .zoomMaskMove(e); break ; case "mouseleave" : //鼠标滑出后,显示遮罩和右侧大图片 this .zoomMask.style.display= "none" ; this .zoomCont.style.display= "none" ; //移除鼠标移动和滑出事件 this .zoomSmall.removeEventListener( "mousemove" , this .mouseHandlers); this .zoomSmall.removeEventListener( "mouseleave" , this .mouseHandlers); break ; } } zoomMaskMove(e){ //遮罩移动 let rect= this .elem.getBoundingClientRect(); //计算let和top的值,等于鼠标的坐标-父容器的left值-遮罩的一半宽 let x=e.clientX-rect.x-Zoom.mask_width/2; let y=e.clientY-rect.y-Zoom.mask_width/2; //判断left和top的范围 if (x<0) x=0; if (x>Zoom.small_width-Zoom.mask_width) x=Zoom.small_width-Zoom.mask_width; if (y<0) y=0; if (y>Zoom.small_width-Zoom.mask_width) y=Zoom.small_width-Zoom.mask_width; this .zoomMask.style.left=x+ "px" ; this .zoomMask.style.top=y+ "px" ; //大图片移动 this .zoomContMove(x,y); } zoomContMove(_x,_y){ //计算大图片的背景定位,公式:zoom的宽/mask的宽=zoom的背景left值/mask的left值 let x=-Zoom.zoom_width/Zoom.mask_width*_x; let y=-Zoom.zoom_width/Zoom.mask_width*_y; this .zoomCont.style.backgroundPosition=x+ "px " +y+ "px" ; } static setStyle(){ //设置样式 if (Zoom.styles) return ; Zoom.styles= true ; Utils.insertCss( ".zoomContainer" ,{ width:Zoom.small_width+ "px" , height:Zoom.small_width+ "px" , position: "relative" }) Utils.insertCss( ".zoomSmall" ,{ width:Zoom.small_width+ "px" , height:Zoom.small_width+ "px" , border: "1px solid #000" , backgroundSize: "100% 100%" , position: "absolute" , left: "0px" , top: "0px" }) Utils.insertCss( ".zoomMask" ,{ width: this .mask_width + "px" , height: this .mask_width + "px" , backgroundColor: "rgba(200,170,0,0.3)" , position: "absolute" , left: "0px" , top: "0px" , display: "none" }) Utils.insertCss( ".zoomContent" ,{ width: this .zoom_width + "px" , height: this .zoom_width + "px" , border: "1px solid #ccc" , position: "absolute" , left: ( this .small_width + 2) + "px" , top: "0px" , display: "none" }) } } |
IconList.js文件,创建下方图标列表,并完成翻页效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
import Utils from "./Utils.js" ; import Zoom from "./Zoom.js" ; export default class IconList{ static styles= false ; static num=5; //每页显示的图标数 static gap=0; //表示li的左右间距 position=0; //当前显示的图标为第几页 x=0; //列表的left值 prepIcon; //上一个点击的图标 static SET_BG_IMG= "set_bg_img" ; constructor(list){ this .list=list; this .elem= this .createE(); } createE(){ //创建外层容器 let div=Utils.createE( "div" ); div.className= "iconContainer" ; div.innerHTML=`<img class= "prevBtn" src= "./img/prev.png" ><div class= "iconListCont" >${ this .createIcon()}</div><img class= "nextBtn" src= "./img/next.png" >`; //设置css样式 IconList.setStyles( this .list); //获取元素 Utils.getIdElem(div, this ); //外层容器监听点击事件 div.addEventListener( "click" ,e=> this .clickHandler(e)); //图标列表监听鼠标滑过事件 this .iconList.addEventListener( "mouseover" ,e=> this .mouseHandler(e)); //默认显示第一个图标的边框 this .setIconState( this .iconList.firstElementChild); //默认显示第一个图片 this .setBgImg( this .iconList.firstElementChild.firstElementChild); return div; } createIcon(){ //创建图标列表 let str=`<ul class= "iconList clearfix" id= "iconList" >`; this .list.forEach(item=>{ str+=`<li><img src= "${item}" ></li>`; }) str+= "</ul>" ; return str; } clickHandler(e){ let src=e.target.src; //如果点击的不是左右按钮,直接跳出 if (!/prev/.test(src)&&!/next/.test(src)) return ; //每一个li的实际宽度,width+border+margin let liWidth=54+4+IconList.gap; //page为一共有几个整数页 let page=Math.floor( this .list.length/IconList.num)-1; //remainder为最后不够一页的剩余图标数 let remainder= this .list.length%IconList.num; if (/prev/.test(src)){ //如果点击的是上一页按钮 if ( this .x===0) return ; //移动到最后一页时 if ( this .position===0&&remainder>0){ //移动的距离加等于li宽度*剩余图标数 this .x+=liWidth*remainder; } else if ( this .position<=page){ this .position--; //移动的距离加等于li的宽度*每页显示的图标数(5个) this .x+=liWidth*IconList.num; } } else if (/next/.test(src)){ //如果点击的是下一页按钮 if ( this .x===-( this .list.length-IconList.num)*liWidth) return ; if ( this .position===page&&remainder>0){ //移动的距离减等于li宽度*剩余图标数 this .x-=liWidth*remainder; } else if ( this .position<page){ this .position++; //移动的距离减等于li的宽度*每页显示的图标数(5个) this .x-=liWidth*IconList.num; } } //设置图标列表的left值 this .iconList.style.left= this .x+ "px" ; } mouseHandler(e){ //如果滑过的不是Img标签,直接跳出 if (e.target.constructor!==HTMLImageElement) return ; //设置背景图片 this .setBgImg(e.target); //设置当前滑过图标的样式 this .setIconState(e.target.parentElement); } setIconState(target){ //移除上一个滑过图标的active样式 if ( this .prepIcon) Utils.removeClass( this .prepIcon, "active" ); //将当前滑过的对象赋值给this.prepIcon this .prepIcon=target; //给当前滑过图标增加active样式 Utils.addClass( this .prepIcon, "active" ); } setBgImg(target){ //抛发事件,将当前图片的src传过去 let src=target.src.replace( "_icon" , "" ); let evt= new Event(IconList.SET_BG_IMG); evt.src=src; document.dispatchEvent(evt); } static setStyles(list){ //设置样式 if (IconList.styles) return ; IconList.styles= true ; Utils.insertCss( ".iconContainer" ,{ width:Zoom.small_width+2+ "px" , height: "58px" , position: "absolute" , top: Zoom.small_width+2+ "px" , left: "0px" , }) Utils.insertCss( ".iconContainer>img" ,{ width: "22px" , height: "32px" , cursor: "pointer" , position: "absolute" , top: "13px" , }) Utils.insertCss( ".prevBtn" ,{ left: "8px" }) Utils.insertCss( ".nextBtn" ,{ right: "8px" }) Utils.insertCss( ".iconListCont" ,{ width:Zoom.small_width-30*2+ "px" , height: "58px" , position: "relative" , left: "30px" , overflow: "hidden" }) IconList.gap=((Zoom.small_width-30*2)-(54+4)*IconList.num)/IconList.num; Utils.insertCss( ".iconList" ,{ width:(54+4+IconList.gap)*list.length+ "px" , listStyle: "none" , padding: "0px" , margin: "0px" , position: "absolute" , left: "0px" , top: "0px" , transition: "all .3s" }) Utils.insertCss( ".iconList li" ,{ float: "left" , width: "54px" , height: "54px" , margin: "0px " +IconList.gap/2+ "px" , cursor: "pointer" , border: "2px solid transparent" }) Utils.insertCss( ".iconList li.active" ,{ borderColor: "#f00" }) Utils.insertCss( ".iconList li>img" ,{ width: "54px" , height: "54px" }) Utils.insertCss( ".clearfix::after" ,{ content: "\".\"" , display: "block" , height: "0px" , clear: "both" , overflow: "hidden" , visibility: "hidden" }) } } |
Utils.js文件,是一个工具包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
export default class Utils{ static createE(elem,style,prep){ elem=document.createElement(elem); if (style) for (let prop in style) elem.style[prop]=style[prop]; if (prep) for (let prop in prep) elem[prop]=prep[prop]; return elem; } static appendTo(elem,parent){ if (parent.constructor === String) parent = document.querySelector(parent); parent.appendChild(elem); } static insertBefore(elem,parent){ if (parent.constructor === String) parent=document.querySelector(parent); parent.insertBefore(elem,parent.firstElementChild); } static randomNum(min,max){ return Math.floor(Math.random*(max-min)+min); } static randomColor(alpha){ alpha=alpha||Math.random().toFixed(1); if (isNaN(alpha)) alpha=1; if (alpha>1) alpha=1; if (alpha<0) alpha=0; let col= "rgba(" ; for (let i=0;i<3;i++){ col+=Utils.randomNum(0,256)+ "," ; } col+=alpha+ ")" ; return col; } static insertCss(select,styles){ if (document.styleSheets.length===0){ let styleS=Utils.createE( "style" ); Utils.appendTo(styleS,document.head); } let styleSheet=document.styleSheets[document.styleSheets.length-1]; let str=select+ "{" ; for ( var prop in styles){ str+=prop.replace(/[A-Z]/g, function (item){ return "-" +item.toLocaleLowerCase(); })+ ":" +styles[prop]+ ";" ; } str+= "}" styleSheet.insertRule(str,styleSheet.cssRules.length); } static getIdElem(elem,obj){ if (elem.id) obj[elem.id]=elem; if (elem.children.length===0) return obj; for (let i=0;i<elem.children.length;i++){ Utils.getIdElem(elem.children[i],obj); } } static addClass(elem,className){ let arr=(elem.className+ " " +className).match(/\S+/g); arr=arr.filter((item,index)=>arr.indexOf(item,index+1)<0) elem.className=arr.join( " " ); } static removeClass(elem,className){ if (!elem.className) return ; let arr=elem.className.match(/\S+/g); let arr1=className.match(/\S+/g); arr1.forEach(item=>{ arr=arr.filter(t=>t!==item) }) elem.className=arr.join( " " ); } static hasClass(elem,className){ if (!elem.className) return false ; let arr=elem.className.match(/\S+/g); let arr1=className.match(/\S+/g); let res; arr1.forEach(item=>{ res= arr.some(it=>it===item) }) return res; } static loadImg({list,basePath,callback}){ if (!list || list.length===0) return ; if (basePath) list=list.map(item=>basePath+item); let img=Utils.createE( "img" ); img.data={ list:list, callback:callback, resultList:[], num:0 } img.addEventListener( "load" ,Utils.loadImgHandler); img.src=list[img.data.num]; } static loadImgHandler(e){ let data=e.currentTarget.data; data.resultList.push(e.currentTarget.cloneNode( false )); data.num++; if (data.num>data.list.length-1){ e.currentTarget.removeEventListener( "load" ,Utils.loadImgHandler); data.callback(data.resultList); data= null ; return ; } e.currentTarget.src=data.list[data.num]; } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/Charissa2017/article/details/104159002