Vue3 list vertical scrolling (including page turning effect using swiper)

1. Use element-plus table for scrolling:

Needs that can be met: The table scrolls vertically line by line, similar to a revolving lantern.
Unsatisfied needs: The table is paginated and scrolls vertically, which has the effect of turning pages.

Code:
<template>
<el-table
      :data="tableData"
      :show-overflow-tooltip="true"
      class="alarmTable"
    >
    <el-table-column
        type="index"
        width="134"
        align="center"
        label="serial number">
        <template #default="scope">
          <span class="text">{<!-- -->{<!-- -->(scope.$index + 1) + (currentPage-1)*(pageSize)}}</span>
        </template>
      </el-table-column>
      <el-table-column prop="name" label="name" align="left">
        <template #default="scope">
          <span class="name-text">{<!-- -->{<!-- -->scope.row.name}}</span>
        </template>
      </el-table-column>
      <el-table-column prop="money" label="Money" align="center" />
  </el-table>
</template>
<script lang="ts">
import {<!-- --> defineComponent, onMounted, reactive, ref, toRefs, nextTick, onUnmounted } from 'vue'

export default defineComponent({<!-- -->
  name: 'rank',
  setup () {<!-- -->
    //Data type of table
    interface tableType {<!-- -->
      name: string;
      money: number;
    }
    const data = reactive({<!-- -->
      tableData: [] as Array<tableType>, // table data
      currentPage: 1, // Currently displayed page number
      pageSize: 6, //How many pieces of data are displayed on one page of the current table?
      tableDom: {<!-- -->} as HTMLElement, // DOM of table content
    })
    let timeInterval: NodeJS.Timer // timer object
    let tableScroll = ref(true) // Whether scrolling is required

    onMounted(() => {<!-- -->
      //Initialize table data
      list()
      scrollTable()
    })

    onUnmounted(()=> {<!-- -->
      clearInterval(timeInterval)
    })

    //Initialize table data
    const list = () => {<!-- -->
      let arr:Array<tableType> = []
      for(let i = 0; i < 28; i + + ) {<!-- -->
        let randomData = Math.floor(Math.random() * 100)
        let obj = {<!-- -->
          name: 'name' + randomData,
          money: randomData
        }
        arr.push(obj)
      }
      data.tableData = arr
    }
\t
//Table data scrolling
    const scrollTable = () => {<!-- -->
      nextTick(() => {<!-- -->
        // Get the dom of the current table content
        let table = document.getElementsByClassName('alarmTable')[0]
        data.tableDom = (table.getElementsByClassName('el-scrollbar__wrap')[0])! as HTMLElement
        // Put the mouse on the table content to pause scrolling
        data.tableDom.addEventListener('mouseover', () => {<!-- -->
            tableScroll.value = false
        })
        // Move the mouse out of the table content and continue scrolling
        data.tableDom.addEventListener('mouseout', () => {<!-- -->
          tableScroll.value = true
        })
        //
        timeInterval = setInterval(() => {<!-- -->
            if (tableScroll.value) {<!-- -->
              //The distance each time the content is scrolled
              data.tableDom.scrollTop + = 1
              if (data.tableDom.clientHeight + data.tableDom.scrollTop == data.tableDom.scrollHeight) {<!-- -->
                data.tableDom.scrollTop = 0
              }
            }
        }, 10)
      })
    }
    
    return {<!-- -->
      ...toRefs(data)
    }
  }
})
</script>
<style lang="scss" scoped>
.alarmTable {<!-- -->
    margin-top: 40px;
    height: 623px;
    overflow: hidden;
    scroll-behavior: smooth;
}
</style>
<style lang="scss">
  .el-table, .el-table::before,
  .el-table--border .el-table__inner-wrapper::after, .el-table--border::after, .el-table--border::before, .el-table__inner-wrapper::before {< !-- -->
    background: transparent!important;
  }
  .el-table th, .el-table__cell>.cell {<!-- -->
    height: 88px;
    padding: 0;
    font-size: 28px;
    font-weight: 400;
    color: #FFFFFF;
    line-height: 88px!important;
  }
  .el-table thead {<!-- -->
    font-size: 28px;
    font-weight: 600;
    color: #fff!important;
  }
  .el-table tr{<!-- -->
    background: transparent!important;
     & amp;:nth-child(2n) {<!-- -->
      background: rgba(49, 250, 233, 0.1)!important;
    }
  }
  .el-table th.el-table__cell {<!-- -->
    height: 88px;
    padding: 0;
    background: rgba(237, 250, 49, 0.1)!important;
  }
  .el-table tr:hover>td {<!-- -->
    cursor: pointer;
    background-color: rgba(0,148,255,0.3) !important;
  }
  .el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf {<!-- -->
    border-bottom: none!important;
  }
</style>
Effect:

2. Use Swiper to scroll:

1. Document description: https://swiperjs.com/vue

2. Download swiper instructions:

Introducing Autoplay into the higher version (10.0.2) will report an error, so I downloaded the 7.4.1 version (npm install [email protected] code>)

If version 7.4.1 is not easy to use, you can refer to this article: https://blog.csdn.net/qq_36131788/article/details/121083045

3. After successfully installing swiper, introduce css in the main.ts file:

import swiper/css’
Code:
<template>
    <div class="swiper-components">
        <div class="thead">
            <div v-for="(item,index) in theadData" :key="index" class="thead-tr">{<!-- -->{<!-- --> item }}</ div>
        </div>
        <swiper
            :slides-per-view="1"
            :autoplay="{ delay: 2000, disableOnInteraction: false }"
            :direction="'vertical'"
            :scrollbar="{ draggable: false }"
            :loop="true"
            :modules="modules"
            class="swiper-content"
            >
            <swiper-slide v-for="(item, index) in tableData" :key="index">
                <div class="swiper-item" v-for="(subItem, subIndex) in item" :key="subIndex">
                    <div class="swiper-td">{<!-- -->{<!-- --> subItem.index }}</div>
                    <div class="swiper-td">{<!-- -->{<!-- --> subItem.name }}</div>
                    <div class="swiper-td">{<!-- -->{<!-- --> subItem.money }}</div>
                </div>
            </swiper-slide>
            </swiper>
    </div>
  </template>

<script lang="ts">
import {<!-- --> defineComponent, onMounted, reactive, toRefs } from 'vue'
//Introduce swiper core and required modules
import {<!-- -->Autoplay} from 'swiper'
//Introduce the components required by swiper
import {<!-- --> Swiper, SwiperSlide } from 'swiper/vue'

export default defineComponent({<!-- -->
  name: 'SwiperComponents',
  components: {<!-- -->
    Swiper,
    SwiperSlide
  },
  setup () {<!-- -->
    //Data type of table
    interface tableType {<!-- -->
      index: number | string;
      name: string;
      money: number;
    }
    const data = reactive({<!-- -->
      tableData: [] as Array<tableType>[], // Data required for the list
      modules: [Autoplay], // This is the key point of automatic playback. Without this, automatic playback cannot be performed!
      slidesCount: 6, //The number of data for each slide
      theadData: ['serial number', 'name', 'money'] // Table header
    })

    onMounted(() => {<!-- -->
      init()
    })

    //Data initialization
    const init = () => {<!-- -->
      //First get the requested data
      let arr = []
      for (let i = 0; i < 30; i + + ) {<!-- -->
        const obj = {<!-- -->
          index: i + 1,
          name: '987654',
          money: Math.floor(Math.random() * 100)
        }
        arr.push(obj)
      }

      // Process data according to the number to be displayed on a page
      for (let i = 0; i < arr.length; i + = data.slidesCount) {<!-- -->
        let obj = arr.slice(i, i + data.slidesCount)
        data.tableData.push(obj)
      }
    }

    return {<!-- -->
      ...toRefs(data)
    }
  }
})
</script>

  <style lang="scss" scoped>
  .swiper-components {<!-- -->
    margin-top: 40px;
    .thead {<!-- -->
        display: flex;
        justify-content: space-between;
        background: rgba(49,150,250,0.1);
        padding: 24px 40px 24px 34px;
         & amp;-tr {<!-- -->
            font-size: 28px;
            font-weight: 600;
            color: #FFFFFF;
            line-height: 40px;
        }
    }
    .swiper-content {<!-- -->
        height: 528px;
        .swiper-item {<!-- -->
            display: flex;
            justify-content: space-between;
             & amp;:nth-child(2n) {<!-- -->
                background: rgba(49,150,250,0.1);
            }
        }
        .swiper-td {<!-- -->
            padding: 24px 0;
            font-size: 28px;
            font-weight: 400;
            color: #FFFFFF;
            line-height: 40px;
             & amp;:first-child {<!-- -->
                width: 134px;
                text-align: center;
            }
             & amp;:last-child {<!-- -->
                width: 140px;
                margin-right: 40px;
                text-align: center;
            }
        }
    }
  }
  </style>

Effect:

3. Use Swiper to click left and right to turn pages (the style should be adjusted according to actual needs):

<template>
<swiper-slide v-for="(item, index) in 10" :key="index" class="swiper-single">
<div class="video-single">
<div class="video-content">
<video
controls
controlslist="nodownload noplaybackrate"
disablePictureInPicture="true"
disableRemotePlayback="true"
src="//i2.wp.com/www.runoob.com/try/demo_source/movie.mp4"></video>
</div>
<div class="video-name">Video{<!-- -->{<!-- --> index }}</div>
</div>
</swiper-slide>
</template>

<script lang="ts">
import {<!-- --> defineComponent, toRefs } from 'vue'
//Introduce the components required by swiper
import {<!-- --> Swiper, SwiperSlide } from 'swiper/vue'
import {<!-- --> Pagination, Navigation } from 'swiper'

export default defineComponent({<!-- -->
  name: 'VideoDialog',
  components: {<!-- -->
    Swiper,
    SwiperSlide
  },
  setup () {<!-- -->
    const data = reactive({<!-- -->
      modules: [Pagination, Navigation]
    })
    
    return {<!-- -->
      ...toRefs(data)
    }
  }
})
</script>
<style lang="scss">
  .swiper-button-prev, .swiper-button-next {<!-- -->
    cursor: pointer;
    z-index: 200;
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    display: inline-block;
    width: 59px;
    height: 59px;
    background: rgba(49,150,250,0.1);
    border-radius: 3px;
    border: 2px solid #3196FA;
  }
  .swiper-button-prev {<!-- -->
     & amp;::after {<!-- -->
      content: '';
      position: absolute;
      z-index: 5;
      top: 10px;
      left: 4px;
      display: inline-block;
      width: 12px;
      border-right: 18px solid #3196fa;
      border-left: 0 solid transparent;
      border-top: 18px solid transparent;
      border-bottom: 18px solid transparent;
    }
     & amp;::before {<!-- -->
      content: '';
      position: absolute;
      z-index: 6;
      top: 10px;
      left: 8px;
      display: inline-block;
      width: 12px;
      border-right: 18px solid #1c4577;
      border-left: 0 solid transparent;
      border-top: 18px solid transparent;
      border-bottom: 18px solid transparent;
    }
  }
  .swiper-button-next {<!-- -->
    margin-left: 154px;
     & amp;::after {<!-- -->
      content: '';
      position: absolute;
      z-index: 5;
      top: 10px;
      right: 4px;
      display: inline-block;
      width: 12px;
      border-left: 18px solid #3196fa;
      border-right: 0 solid transparent;
      border-top: 18px solid transparent;
      border-bottom: 18px solid transparent;
    }
     & amp;::before {<!-- -->
      content: '';
      position: absolute;
      z-index: 6;
      top: 10px;
      right: 8px;
      display: inline-block;
      width: 12px;
      border-left: 18px solid #1c4577;
      border-right: 0 solid transparent;
      border-top: 18px solid transparent;
      border-bottom: 18px solid transparent;
    }
  }
  .swiper-pagination{<!-- -->
    z-index: 200;
    position: absolute;
    bottom: 23px;
    left: 630px;
    width: 95px;
    white-space: nowrap;
    font-size: 24px;
    font-weight: 400;
    color: #CCCCCC;
    line-height: 14px;
  }
  .swiper-pagination-current {<!-- -->
    color: #3196FA;
  }
</style>

Effect: