制作一个无限无缝轮播滚动的通知栏

最近使用swiper这个库,突然想做个无限轮播滚动的通知栏。效果如下图:

思路

这东西其实是一个比较特殊的轮播图效果,所以主要参照轮播图的开发流程来做就差不多了。

  1. 需要一个显示的内容的盒子包裹内容,高度按照内容的整体高度(cilentHeight )来决定,我比较懒,直接写死(差不多放下4个内容 ),四个内容为一版显示,后续都是根据4个为一组进行轮播显示
  2. 因为要进行滚动显示,只需要给内容外层容器添加translateY配合transition来达到滚动和缩放的动画效果。
  3. 后续需要计算translateY的每一次滚动的距离,所以内容之间最好不要有间隔,比如margin之类的间隔,因为这样子更加简单,后面计算的时候直接滚动对应的高度就好了。
  4. 要实现无限无缝滚动,就是要参照轮播图的无缝滚动了,原来其实就是复制第一份视图容器所能容下的内容数据,放到数据最后方,当滚动到最后的复制数据时,停止对应的动画,然后直接初始化数据我这里做得不够好,希望大伙帮我优化一下,哈哈哈。

实现

结构

HTML 复制代码
<!-- container就是视图容器,这里写死一个高度 -->
<div class="container">
<!-- 内容外层容器  -->
    <ul :ref="(el) => ulRef = el" class="user-list flex flex-col flex-aic" :style="{
        transform: `translateY(${translateY}px)`
      }">
      <!-- 内容 -->
      <li class="flex flex-aic flex-jcc" :ref="(el) => itemRef = el" v-for="(item,index) in list">
        <div :id="`User${index}`" class="flex flex-aic gap-10 w-100p h-100p" :style="userStyle(index)">
          <span>{{ item.name }}</span>
          <span>has placed an enquiry on BetterYou products of <span style="color: #1A237C">{{ item.money }}</span>
          pieces</span>
        </div>
      </li>
    </ul>
  </div>

样式:注释记得删掉

css 复制代码
 // 写死高度
  .container {
    margin: 100px auto;
    height: 380px; // 这里是可以通过计算获得的,比较懒
    overflow: hidden;
  }

  li::marker {
    content: ""
  }

  .user-list li {
    font-size: 18px;
    font-family: Microsoft YaHei-Bold, Microsoft YaHei;
    font-weight: 700;
    color: #1A237C;
    padding-bottom: 30px; // 这里是为了给内容之间看起来存在间隔


  }

  li div {
    padding: 18px 40px;
    width: fit-content;
    background: rgba(182, 182, 182, 0.1);
    box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.05);
    border-radius: 10px 10px 10px 10px;
    text-align: center;
  }

  li span:last-child {
    color: #000000;
  }

逻辑

js 复制代码
 import { defineComponent, ref,defineProps,computed,onMounted,onUnmounted } from 'vue';
// 原来使用TS写的,但是掘金居然不支持VUE3的TS版本,只能随便搬过来了
export default defineComponent({
  setup() {
    
const data = ref([
    {
      name: "遥遥领先",
      money: 99999
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    },
    {
      name: "大米",
      money: 7777
    }
  ])

const ulRef = ref(null) // 内容外层容器
const itemRef = ref(null) // 内容容器
const timer = ref(null)
const translateY = ref(0) // 内容外层容器滚动Y轴距离
const activeIndex = ref(0) // 当前最大的活动内容(就是视图容器中显示的第一个内容)
const delayed = ref(1) // 动画持续时间

const list = computed(
  () => data.value?.length
    ? [
      ...data.value,
      ...data.value.filter((item, index) => index < 4) // 将最前面的四个内容复制一份放到最后
    ]
    : []
)
const disY = computed(() => itemRef.value?.clientHeight ?? 90)
const userStyle = computed(() => (index) => {
  let style = {}
  switch (index) {
    case activeIndex.value:
      style['transform'] = `scale(1)`
      style['transition'] = `all ${delayed.value}s`
      break
    case activeIndex.value + 1:
      style['transform'] = `scale(.9)`
      style['transition'] = `all ${delayed.value}s`
      break
    case activeIndex.value + 2:
      style['transform'] = `scale(.8)`
      style['transition'] = `all ${delayed.value}s`
      break
    case  activeIndex.value + 3:
      style['transform'] = `scale(.7)`
      style['transition'] = `all ${delayed.value}s`
      break
    case  activeIndex.value + 4:
    // 视图之外第五个内容的样式,这样子动画看起来就不会很突兀
      style['transform'] = `scale(.6)`
      style['transition'] = `all ${delayed.value}s`
      break
    default:
      // 视图容器之外(除了第五个内容)内容样式
      style['transform'] = `scale(1)`
      style['transition'] = 'none'
      break
  }
  if (activeIndex.value === 0) style['transition'] = 'none' // 循环了一轮后,显示了复制前面的四个内容之后
  return style
})

onMounted(() => {
  start()
})
onUnmounted(() => {
  clearInterval(timer.value)
})

function start() {
  timer.value = setInterval(() => {
    if (activeIndex.value === list.value.length - 4) {
      // 循环了一轮之后初始化
      ulRef.value.style.transition = 'none'
      translateY.value = 0
      activeIndex.value = 0
    } else {
      // 循环轮播
      ulRef.value.style.transition = `all ${delayed.value}s`
      translateY.value -= disY.value
      activeIndex.value += 1
    }

  }, delayed.value * 1000)
}

    return {
      list,
      translateY,
      ulRef,
      itemRef,
      timer,
      translateY,
      activeIndex,
      delayed,
      userStyle
    };
  },
});

效果展示

cdvtSAbR - 码上掘金 (juejin.cn)

相关推荐
Csvn2 小时前
OpenSpec 详细使用教程
前端
之歆3 小时前
Day19_LESS 完全指南——从入门到工程实践
前端·css·less
云水一下3 小时前
HTML5 从入门到精通:实战收官——从零搭建完整静态网站,综合运用所有知识
前端·html5
不总是4 小时前
Windows 系统 Node.js 免安装版(zip)安装与配置教程(2026 最新)
前端·windows·node.js
冬奇Lab4 小时前
每日一个开源项目(第105篇):Twenty - 跳出 Salesforce 的圈套,定义现代开源 CRM
前端·后端·开源
zhangyao9403304 小时前
开发pc端时,表格的高度怎么设置才能铺满页面
前端·javascript·elementui
kjs--5 小时前
浏览器书签执行脚本
前端
之歆5 小时前
Day16_JavaScript 轮播图与事件工程实战(下篇)
服务器·开发语言·前端·javascript·网络·性能优化
沄媪5 小时前
CSRF 跨站请求伪造
前端·ctf·csrf
kyriewen6 小时前
我关掉了Copilot:因为我写的代码出现在了别人的建议里
前端·javascript·ai编程