本文實例為大家分享了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