js+css实现小红书图片轮播指示灯效果(选中高亮灯自动居中)
导言
近期实现一个需求,大概就是类似小红书图片轮播指示灯那样,固定只显示n个指示灯,若n个灯前方或者后方存在更多图,则n个中最前方或者最后方的灯缩小展示。直接上图:
【不会上传视频。。就凑合看下图吧
产品表示:我要一模一样的,也是五个灯,切换图片时,指示灯自动滚动,要让选中的居中,前方或者后方有更多图,最前或者最后的灯要缩小显示。
实现效果
效果1
效果2
效果3
构思方案
看了小红书的实际效果后,个人认为实现方案大概是:全部的灯都渲染出来,但是只留出五个灯的显示宽度,其他的overflow: hidden掉;再根据选中灯的位置,js控制横向滚动,将选中灯滚动到视区中间;至于缩小的灯,则需要根据每个灯的index去判断是否缩小显示。但是具体哪些灯要缩小显示呢,感觉是一个比较复杂的条件,一旦搞不好可能写完了自己在看也看不明白了,决定先去网上找找参考方案。
参考方案
https://blog.csdn.net/qq_44656685/article/details/115376854
思路大概是根据总数量和选中灯的index,按照上面的是实现效果一样,分几个条件,不同条件渲染不同的灯和小灯,但是存在一个问题:这是一个纯静态的,没有切换过渡的效果,特别在图数量较多时,处于效果2的条件就会一直是纯静态的,看起来很奇怪。
综合考虑后,决定按照构思方案去实现,不过参考方案也给了一定的启发,那就是哪些灯缩小显示的条件,这位好人直接给出来了,稍微改改就可以用了。
总结如下:
果然比较复杂。。。哈哈哈哈
实现方案
⬆️先放一个链接在这里
核心逻辑:
使选中的点滚动至视区中间
搭配css,dotWrapper这个样式,就是为了控制视区宽度(为5个点+4个间隔的距离),在通过js强制控制scrollLeft使选中点定位到视区中间,window.requestAnimationFrame创造滚动的动画效果
handleScrollDotView() { setTimeout(() => { const selected = document.querySelector('.selectedDot'); const selectedLeft = selected.getBoundingClientRect().x; // 将选中的点偏移至中间 const scrollDom = document.querySelector('.dotWrapper'); const offset = selectedLeft - (window.innerWidth - 8) / 2; const duration = 1000; const frames = Math.round(duration / 1000 * 16); let frame = 0; // 过渡帧数 const animate = () => { scrollDom.scrollLeft += offset / frames; if (++frame < frames) { window.requestAnimationFrame(animate); } }; window.requestAnimationFrame(animate); }, 100); }
点缩放的条件:【懒得搞格式了
<div className="dotWrapper"> { new Array(this.state.total).fill({}).map((_, index) => { return <div className={ `dot ${index === this.state.selectedIndex && 'selectedDot'} ${this.state.total > 5 && ( (this.state.selectedIndex < 3 && index >= 4) || (this.state.selectedIndex >= 3 && this.state.selectedIndex < this.state.total - 3 && Math.abs(index - this.state.selectedIndex) >= 2) || (this.state.selectedIndex >= this.state.total - 3 && index <= this.state.total - 5) ) && 'smallDot'}`} key={index} />; }) } </div>