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

最近使用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)

相关推荐
玩电脑的辣条哥2 小时前
Python如何播放本地音乐并在web页面播放
开发语言·前端·python
ew452182 小时前
ElementUI表格表头自定义添加checkbox,点击选中样式不生效
前端·javascript·elementui
suibian52352 小时前
AI时代:前端开发的职业发展路径拓宽
前端·人工智能
画月的亮2 小时前
element-ui 使用过程中遇到的一些问题及解决方法
javascript·vue.js·ui
Moon.92 小时前
el-table的hasChildren不生效?子级没数据还显示箭头号?树形数据无法展开和收缩
前端·vue.js·html
m0_526119402 小时前
点击el-dialog弹框跳到其他页面浏览器的滚动条消失了多了 el-popup-parent--hidden
javascript·vue.js·elementui
垚垚 Securify 前沿站2 小时前
深入了解 AppScan 工具的使用:筑牢 Web 应用安全防线
运维·前端·网络·安全·web安全·系统安全
工业甲酰苯胺5 小时前
Vue3 基础概念与环境搭建
前端·javascript·vue.js
lyj1689975 小时前
el-tree选中数据重组成树
javascript·vue.js·elementui
mosquito_lover16 小时前
怎么把pyqt界面做的像web一样漂亮
前端·python·pyqt