You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

实现方案

  1. 添加悬停事件获取索引
    在缩略图的<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);
}
  1. 绑定主图到模板
    修改主图区域的<img>标签,绑定到组件变量:
<img [src]="currentMainImage" alt="商品大图">
  1. 优化悬停样式反馈
    添加CSS样式增强交互体验:
.slide-box ul li:hover {
  border-color: #2874f0;
  cursor: pointer;
}
.inside-li img.active {
  border: 2px solid #2874f0;
}

内容的提问来源于stack exchange,提问作者ADeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:38:11