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

Posted 许青叶的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 基于原生动画的自动滚动表格相关的知识,希望对你有一定的参考价值。

前言

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

原理

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

其他功能

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

代码

<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: `$heightpx`,
      ,
    ],
    
      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>

参考

vue的滚动条插件vue-scroll

参考技术A 最近在开发Vue项目时,需要实现一个页面的局部滚动条功能。以前实现此类功能都是使用的iframe原生的滚动条功能,保证内容只在div块内滚动,别的地方不影响。
据尝试,发现Iview等组件库都没有符合这种情况的组件,于是查找了其他组件,最终选用了vue-scroll插件。

vuescroll 是一个基于 vue.js 2.X 虚拟滚动条, 它支持定制滚动条的样式,检测内容尺寸变化、能够使内容分页、支持上拉-刷新,下推加载等诸多特性。

(1)拥有原生滚动条的滚动行为
(2)可以定制滚动条的样式(包括颜色、尺寸、位置、透明度、是否保持显示等)
(3)在模式之间自由切换
(4)能够通过设置滚动动画来平滑地滚动
(5)拉取刷新和推动加载
(6)支持分页模式(每次滑动整个页面)
(7)支持快照模式(每次滑动滚动一个用户定义的距离)
(8)可以检测内容尺寸发生变化

在components中再注册一下

这两种引入方式都可以,引入后用vuescroll包裹需要滚动的部分

在data中写明需要修改的配置项

以上是关于vue 基于原生动画的自动滚动表格的主要内容,如果未能解决你的问题,请参考以下文章

vue表格自动滚动

vue 滚动条选中元素自动滚动到可视区域里居中显示

[vue开发记录]vue仿ios原生datepicker实现

怎么能实现div里的滚动条滚动时有动画效果

vue的滚动条插件vue-scroll

Vuescroll 是一个基于 vue.js 2.X的虚拟滚动条