Angular中实现鼠标悬停图片获取索引及预览功能求助
问题需求
- 实现类似电商商品页的图片盒子功能:侧边展示缩略图列表,主区域展示大图,支持缩略图悬停切换主图,同时缩略图列表可上下滚动切换显示的缩略图
- 已完成侧边栏缩略图滚动功能,需要实现鼠标悬停缩略图时获取对应图片的索引及详情
- 实现悬停缩略图时同步切换主区域的预览大图效果
现有代码如下:
Angular 组件代码
@ViewChild('hello',{static:false}) FirstRef!:ElementRef; @ViewChild('next',{static:false}) Next!:ElementRef; @ViewChild('prev',{static:false}) Prev!:ElementRef; SideImagesIcons=['../../../../assets/Product/p1.webp','../../../../assets/Product/p2.webp','../../../../assets/Product/p3.webp', '../../../../assets/Product/p4.webp','../../../../assets/Product/p5.webp','../../../../assets/Product/p6.webp','../../../../assets/Product/p7.webp' ,'../../../../assets/Product/p8.webp'] SideImages=['../../../assets/Product/p1.webp','../../../assets/Product/p2.webp','../../../assets/Product/p3.webp','../../../assets/Product/p4.webp' ,'../../../assets/Product/p5.webp','../../../assets/Product/p6.webp','../../../assets/Product/p7.webp','../../../assets/Product/p8.webp','../../../assets/Product/p9.webp'] imageArrayToDisplay:string[]=[]; displaySize=5; displayIndex=0; startIndex=0; selectedIndex=0; prevIndex=this.displaySize; ngOnInit(): void { this.imageArrayToDisplay=this.SideImagesIcons.slice(this.startIndex,this.currentIndex); console.log("current index = "+this.currentIndex+"\nDisplay Index "+this.displayIndex+"\nStart Index"+this.startIndex+"\nPrev Index"+this.prevIndex); } prevClick(){ this.prevIndex=this.startIndex-1; if(this.displayIndex>this.displaySize && this.prevIndex>=0) { this.displayIndex--; this.imageArrayToDisplay=this.SideImagesIcons.slice(this.prevIndex,this.displayIndex) this.startIndex--; this.Next.nativeElement.style.display='block'; } this.currentIndex=this.displayIndex; if(this.prevIndex<=0) { this.Prev.nativeElement.style.display='none'; } console.log("current index = "+this.currentIndex+"\nDisplay Index "+this.displayIndex+"\nStart Index"+this.startIndex+"\nPrev Index"+this.prevIndex); } currentIndex=this.displaySize; nextClick(){ this.displayIndex=this.currentIndex+1; this.startIndex+=1; //this loop will run till to show the images till it reaches the last image if(this.displayIndex>this.displaySize && this.displayIndex <=this.SideImagesIcons.length) { this.imageArrayToDisplay=this.SideImagesIcons.slice(this.startIndex,this.displayIndex) this.currentIndex++; this.Prev.nativeElement.style.display='block'; } //this will handle if we reaches to last image else if(this.currentIndex<=this.SideImagesIcons.length) { this.currentIndex=this.SideImagesIcons.length; this.displayIndex=this.currentIndex; this.startIndex=(this.SideImagesIcons.length-this.displaySize); this.Next.nativeElement.style.display='none'; } console.log("current index = "+this.currentIndex+"\nDisplay Index "+this.displayIndex+"\nStart Index"+this.startIndex); }
CSS 样式代码
.flex-container { display: flex; /* align-items: center; */ flex-direction: column; } .container { align-content: center; } .box { display: flex; } .side { width: 108px; height: 400px; border: 1px solid gray; overflow-y: hidden; } .side::-webkit-scrollbar { display: none; } .slide-box { position: relative; width: 100%; height: 500px; border: 1px solid red; } .slide-box ul { transition: -webkit-transform .4s ease-in-out; transition: transform .4s ease-in-out; transition: transform .4s ease-in-out, -webkit-transform .4s ease-in-out; transform: translateY(0px); list-style: none; } .slide-box ul li { width: 64px; height: 64px; border: 1px solid green; } .inside { padding: 5px; width: 100%; height: 100%; position: relative; } .inside-li { width: 100%; height: 100%; } .inside-li img { max-height: 100%; max-width: 100%; position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); } .btn-prev { position: absolute; top: 0%; left: 39%; width: 64%; display: none; } .btn-next { width: 64%; position: absolute; bottom: 32%; left: 37%; } .enlarge-box { width: 400px; height: 400px; border: 1px solid black; } .inside-img-box { padding: 5px; } .inside-img-box .inside-li img { max-height: 99%; max-width: 100%; position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%); }
HTML 模板代码
<div class="flex-container"> <div class="row"> <div class="col-6"> <div class="container"> <div class="box"> <div class="side"> <div class="slide-box"> <ul> <li *ngFor="let prod of imageArrayToDisplay; let i=index"> <div class="inside"> <div class="inside-li"> <img [src]="prod" alt="" [ngClass]="{'active':selectedIndex ===i}"> {{i}} </div> </div> </li> </ul> <button #prev class="btn-primary btn-prev" (click)="prevClick()">Prev</button> <button #next class="btn-success btn-next" (click)="nextClick()">Next</button> </div> </div> <div class="enlarge-box"> <div class="image-box"> <ul> <li> <div class="inside-img-box"> <div class="inside-li"> <img src="../../../assets/Product/p1.webp" alt=""> </div> </div> </li> </ul> </div> </div> </div> </div> </div> <div class="col-6"> <p #hello>Hello world</p> </div> </div> </div>
实现方案
- 添加悬停事件获取索引
在缩略图的<li>标签上添加鼠标进入事件,传递当前循环索引和图片数据:
<li *ngFor="let prod of imageArrayToDisplay; let i=index" (mouseenter)="onThumbnailHover(i, prod)"> <!-- 原有内容 --> </li>
组件中实现处理方法,计算全局索引并更新主图:
currentMainImage: string = this.SideImages[0]; onThumbnailHover(index: number, imageSrc: string) { this.selectedIndex = index; // 计算全局索引(因imageArrayToDisplay是切片后的数组) const globalIndex = this.startIndex + index; this.currentMainImage = this.SideImages[globalIndex]; console.log('当前悬停全局索引:', globalIndex, '缩略图地址:', imageSrc); }
- 绑定主图到模板
修改主图区域的<img>标签,绑定到组件变量:
<img [src]="currentMainImage" alt="商品大图">
- 优化悬停样式反馈
添加CSS样式增强交互体验:
.slide-box ul li:hover { border-color: #2874f0; cursor: pointer; } .inside-li img.active { border: 2px solid #2874f0; }
内容的提问来源于stack exchange,提问作者ADeveloper
相关产品推荐
相关产品推荐

