js+css实现小红书图片轮播指示灯效果(选中高亮灯自动居中)

导言

近期实现一个需求,大概就是类似小红书图片轮播指示灯那样,固定只显示n个指示灯,若n个灯前方或者后方存在更多图,则n个中最前方或者最后方的灯缩小展示。直接上图:

【不会上传视频。。就凑合看下图吧

 产品表示:我要一模一样的,也是五个灯,切换图片时,指示灯自动滚动,要让选中的居中,前方或者后方有更多图,最前或者最后的灯要缩小显示。

 

实现效果

效果1 

 

效果2 

 

效果3

构思方案

看了小红书的实际效果后,个人认为实现方案大概是:全部的灯都渲染出来,但是只留出五个灯的显示宽度,其他的overflow: hidden掉;再根据选中灯的位置,js控制横向滚动,将选中灯滚动到视区中间;至于缩小的灯,则需要根据每个灯的index去判断是否缩小显示。但是具体哪些灯要缩小显示呢,感觉是一个比较复杂的条件,一旦搞不好可能写完了自己在看也看不明白了,决定先去网上找找参考方案。

参考方案

https://blog.csdn.net/qq_44656685/article/details/115376854

思路大概是根据总数量和选中灯的index,按照上面的是实现效果一样,分几个条件,不同条件渲染不同的灯和小灯,但是存在一个问题:这是一个纯静态的,没有切换过渡的效果,特别在图数量较多时,处于效果2的条件就会一直是纯静态的,看起来很奇怪。

综合考虑后,决定按照构思方案去实现,不过参考方案也给了一定的启发,那就是哪些灯缩小显示的条件,这位好人直接给出来了,稍微改改就可以用了。

总结如下:

显示为小点的条件:总数大于5且 (selectedIndex<3且index>=4 || selectedIndex>=3且selectedIndex<总数-3且index与selectedIndex绝对值差>=2 || selectedIndex>总数-3且index<=总数-5)

果然比较复杂。。。哈哈哈哈

实现方案

CODEPEN

⬆️先放一个链接在这里

核心逻辑:

使选中的点滚动至视区中间

搭配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>

 

posted @ 2022-02-08 17:50  sue7  阅读(856)  评论(0编辑  收藏  举报