废话不多说,先贴效果图
如何实现一个无缝无限轮播时间轴...-LMLPHP

看图片可以把这个分割成两部分
1.时间轴
2.图片展示

  1. 首先来分析一下时间轴
    可视范围这样
    如何实现一个无缝无限轮播时间轴...-LMLPHP
    实际长度
    如何实现一个无缝无限轮播时间轴...-LMLPHP
    操作
    给实际长度添加动画效果
    css部分
    :style="{ '--translateX' : translateX }"
    transform: translateX(calc(var(--translateX) * 1px));//1px是因为要用postcss转rem
    transition: transform 0.6s ease-out;
    js部分
    const translateX = ref(0);
    这就是主要实际长度的主要代码,是不是很简单translateX 的值根据自己需求偏移量计算
  2. 接下来分析时间点:
    分析一波:点主要是间隔分布,用间隔倍数来绝对定位确定每个点的位置
    const dots = ref([])点的数组
    const dotSpacing = 251.5;点间距
    如何实现一个无缝无限轮播时间轴...-LMLPHP
    css部分
    :style="{'--x': ${index * dotSpacing}}"
    left: calc(var(--x) * 1px);
    确定好样式了接下来就来实现点击轮播了
    先实现位置的重新计算direction 是传的值,1,-1表示左右🙂
    const newPosition = Number((translateX.value + direction * dotSpacing));
    将值赋给偏移量就实现动画了
    translateX.value = newPosition;
    是不是比较简单嘿!
    那怎么实现无限无缝的轮播呢?
  3. 无限轮播
    无缝循环轮播的要点就是:
    1.前后复制一组数据,避免出现空白
    2.在复制的数据在到达另一个边界的时候,回到原来的位置,利用屏幕刷新率,也就是帧率骗过用户的眼睛,达到无缝循环的视觉错觉
    如何实现一个无缝无限轮播时间轴...-LMLPHP
    前后各复制一组数据
    const clonedDots = [ ...dots.map(d => ({ ...d, cloned: true })), ...dots, ...dots.map(d => ({ ...d, cloned: true })), ];
    const newPosition = Number((translateX.value + direction * dotSpacing));获得偏移量
    if (newPosition <= -(dots.length * dotSpacing))如果b到达a的边界
    translateX.value = newPosition继续进行偏移
    translateX.value = 0;偏移完成后回到原点
    transition: transform 0.6s ease-out因为我们设置了过渡效果,所以会有动画回到原点
    那么我们就应该在b到达a点后禁用过渡立即重置,这里使用的是定时器,然后我们在下一帧的时候重新启用过渡效果
    setTimeout(() => {
    trackRef.value!.style.transition = 'transform 0s';
    translateX.value = 0;
    setTimeout(() => {
    trackRef.value!.style.transition = 'transform 0.6s ease-out';
    },16);
    },600);
    一般屏幕的刷新率都是16,也可以设置为0
    这样我们就实现了无缝循环了,是不是还可以,但还是有点小问题,用户快速点击还是会有瑕疵的
    所以我们应该添加一个防抖函数或者标识
    那我们怎么去给中间的点添加动态的样式呢?
    我这里用的是
    const currentIndex = ref(2);
    根据我自己的需要设置默认第二个是在中间的
    这样就只需要累加的方式就可以了
    direction < 0 ? currentIndex.value ++: currentIndex.value -- ;
    然后重置的也就是比较死板
    currentIndex.value = 2;
    currentIndex.value = dots.length + 1;
    不知道有没有什么更灵活的方式
    这样就完成了时间轴的绘制了👌👌👌
    然后底下的切换也是比较简单
    可以手写或者像我一样使用vue的组件transition-group
    因为我们只需要展示三个就不用去复制了
    const currentItem = computed(() => clonedDots[currentIndex.value]);
    const prevItem = computed(() => clonedDots[currentIndex.value - 1]);
    const nextItem = computed(() => clonedDots[currentIndex.value + 1]);
    const transitionName = ref('slide-next');
    然后用effect函数监听变化
    watch(currentIndex, (newVal, oldVal) => { transitionName.value = newVal > oldVal ? 'slide-next' : 'slide-prev'; });
    剩下的就只需要css去动画就可以了

到这里我们理顺了这个组件的实现方法😄

04-10 15:17