vue 基于原生动画的自动滚动表格

  • vue 基于原生动画的自动滚动表格已关闭评论
  • 10 次浏览
  • A+
所属分类:Web前端
摘要

公司展示大屏需要写滚动表格,通过滚动播放数据,自己随便摸了一个基于动画的自动滚动表格


前言

公司展示大屏需要写滚动表格,通过滚动播放数据,自己随便摸了一个基于动画的自动滚动表格

原理

根据每行的大小和设置的每行滚动时间设置滚动位置,动态添加动画,并把数组第一项移动到最后一项,并订阅该动画结束的事件,在结束时循环执行该操作。

其他功能

  • 可自定义单元格或行
  • 可设置中文映射和取消显示
  • 单元格默认基于网格的响应式大小
  • 鼠标进入时可设置暂停

代码

<template>       <div class="title-container" v-if="!props.noTitle">         <div           v-for="item in props.displayTitles ?? Object.keys(props. List[0])"           :key="item"         >           {{ props.titleMapping?.get(item) ?? item }}         </div>       </div>     <div class="scroll-table">       <div         ref="container"         class="container"         v-on:mouseenter="() => {if(props.pauseWhenMouseEnter) animation?.pause()}"         v-on:mouseleave="() => {if(props.pauseWhenMouseEnter) animation?.play()}"       >         <!-- 行插槽,作用于每个单元格,设置每个单元格的格式,设置 item-container 类型可继承组件定义的样式 -->         <slot           name="row"           v-for="(item, index) in innerList"           :key="item.id"           :item="item"           :index="index"         >           <div class="item-container">             <!-- 默认插槽,作用于每个单元格,设置每个单元格的格式,设置 item 类型可继承组件定义的样式 -->             <slot               v-for="key in props.displayTitles ?? Object.keys(props.list[0])"               :key="key"               :item="Object.keys(item.data).includes(key) ? item.data[key] ? item.data[key] : props.undefinedPlaceholder : props.undefinedPlaceholder"             >               <div class="item">                 {{ Object.keys(item.data).includes(key) ? item.data[key] ? item.data[key] : props.undefinedPlaceholder : props.undefinedPlaceholder }}               </div>             </slot>           </div>         </slot>       </div>     </div> </template>  <script setup lang="ts"> import BaseBox from "./BaseBox.vue"; import {   defineProps,   withDefaults,   onMounted,   computed,   ref,   watch, } from "vue"; const props = withDefaults(   defineProps<{     // 属性名翻译为标题,默认值 属性名列表     titleMapping?: Map<string, string>;     // 列宽,与 grid-template-columns 格式,默认值 repeat(${props.displayTitles?.length ?? Object.keys(props.list[0]).length}, 1fr)     columnSizes?: string;     // 列表     list: Array<any>;     // 展示哪些标题,默认值 全部展示     displayTitles?: Array<string>;     // 走完每一行的时间,默认值 2300 ms     interval?: number;     // 是否显示标题行,默认值 true     noTitle?: Boolean;     // 属性无参数时替换为某字符串,默认值 --     undefinedPlaceholder?: string;     // 鼠标进入时暂停,默认值 true     pauseWhenMouseEnter?: Boolean;   }>(),   {     interval: 2300,     noTitle: false,     undefinedPlaceholder: "--",     pauseWhenMouseEnter: false,   } ); const innerList = ref<Array<{ id: number; data: any }>>(   props.list.map((item, index) => ({ id: index, data: item })) ); const container = ref<HTMLDivElement>(); onMounted(() => {   animate(true); }); // 监控数据列表更新 watch(   () => props.list,   () => {     innerList.value = props.list.map((item, index) => ({       id: index,       data: item,     }));   } ); // 计算列大小 const columnSize = computed(() => {   return (     props.columnSizes ??     `repeat(${       props.displayTitles?.length ?? Object.keys(props.list[0]).length     }, 1fr)`   ); }); // 进行动画 const animation = ref<Animation>(); const animate = (isStart = false) => {   // 计算动画高度   let height = 0;   if (!isStart) {     height = -container.value!.children[1].getBoundingClientRect().height;     // 移动数组第一个到最后一个     let temp = innerList.value.shift();     innerList.value.push(temp!);   } else {     height = -container.value!.children[0].getBoundingClientRect().height;   }   // 进行动画   animation.value = container.value!.animate(     [       {         top: `${height}px`,       },     ],     {       duration: props.interval,       iterations: 1,     }   );   // 监听动画完成后,重新开始动画   animation.value.addEventListener("finish", () => animate(false)); }; </script>  <style scoped lang="scss"> .title-container {   display: grid;   padding: 1rem 0;   font-size: 1.25rem;   background-color: rgb(24, 34, 103);   grid-template-columns: v-bind(columnSize);   text-align: center; } :slotted(.item-container), .item-container {   overflow: hidden;   position: relative;   left: 0;   right: 0;   top: 0;   display: grid;   padding: 1rem 0;   grid-template-columns: v-bind(columnSize); } :slotted(.item), .item {   text-align: center;   font-size: 1.25rem; } .scroll-table {   width: 100%;   height: 100%;   overflow: hidden;    .container {     overflow: hidden;     position: relative;     left: 0;     right: 0;     top: 0;   } } </style> 

参考