🌿一个vue3指令让el-table自动轮播

9,703 阅读3分钟

img

前言

本文开发的工具,是vue3 element-plus ui库专用的,需要对vue3指令概念有一定的了解

​ 最近开发的项目中,需要对项目中大量的列表实现轮播效果,经过一番折腾.最终决定不使用第三方插件,手搓一个滚动指令.

效果展示

列表滚动.webp

实现思路

第一步先确定功能

  • 列表自动滚动
  • 鼠标移入停止滚动
  • 鼠标移出继续滚动
  • 滚轮滚动完成,还可以继续在当前位置滚动
  • 元素少于一定条数时,不滚动

滚动思路

image-20241226223121217.png

image-20241226223310536.png

通过观察el-table的结构可以发现el-scrollbar__view里面放着所有的元素,而el-scrollbar__wrap是一个固定高度的容器,那么只需要获取到el-scrollbar__wrap这个DOM,并且再给一个定时器,不断的改变它的scrollTop值,就可以实现自动滚动的效果,这个值必须要用一个变量来存储,不然会失效

停止和继续滚动思路

设置一个boolean类型变量,每次执行定时器的时候判断一下,true就滚动,否则就不滚动

滚轮事件思路

为了每次鼠标在列表中滚动之后,我们的轮播还可以在当前滚动的位置,继续轮播,只需要在鼠标移出的时候,将当前el-scrollbar__wrapscrollTop赋给前面存储的变量,这样执行定时器的时候,就可以继续在当前位置滚动

不滚动的思路

​ 只需要判断el-scrollbar__view这个容器的高度,是否大于el-scrollbar__wrap的高度,是就可以滚动,不是就不滚动。

大致的思路是这样的,下面上源码

实现代码

文件名:tableAutoScroll.ts

interface ElType extends HTMLElement {
  timer: number | null
  isScroll: boolean
  curTableTopValue: number
}
export default {
  created(el: ElType) {
    el.timer = null
    el.isScroll = true
    el.curTableTopValue = 0
  },
  mounted(el: ElType, binding: { value?: { delay?: number } }) {
    const { delay = 15 } = binding.value || {}
    const tableDom = el.getElementsByClassName(
      'el-scrollbar__wrap'
    )[0] as HTMLElement
    const viewDom = el.getElementsByClassName(
      'el-scrollbar__view'
    )[0] as HTMLElement

    const onMouseOver = () => (el.isScroll = false)
    const onMouseOut = () => {
      el.curTableTopValue = tableDom.scrollTop
      el.isScroll = true
    }

    tableDom.addEventListener('mouseover', onMouseOver)
    tableDom.addEventListener('mouseout', onMouseOut)

    el.timer = window.setInterval(() => {
      const viewDomClientHeight = viewDom.scrollHeight
      const tableDomClientHeight = el.clientHeight

      if (el.isScroll && viewDomClientHeight > tableDomClientHeight) {
        const curScrollPosition = tableDom.clientHeight + el.curTableTopValue
        el.curTableTopValue =
          curScrollPosition === tableDom.scrollHeight
            ? 0
            : el.curTableTopValue + 1
        tableDom.scrollTop = el.curTableTopValue
      }
    }, delay)
  },
  unmounted(el: ElType) {
    if (el.timer !== null) {
      clearInterval(el.timer)
    }
    el.timer = null

    const tableDom = el.getElementsByClassName(
      'el-scrollbar__wrap'
    )[0] as HTMLElement
    tableDom.removeEventListener('mouseover', () => (el.isScroll = false))
    tableDom.removeEventListener('mouseout', () => {
      el.curTableTopValue = tableDom.scrollTop
      el.isScroll = true
    })
  },
}

上面代码中,我在 created中初始化了三个变量,分别用于存储,定时器对象 、是否滚动判断、滚动当前位置。

mounted中我还获取了一个options,主要是为了可以定制滚动速度

用法

  1. 将这段代码放在你的文件夹中

  2. main.ts中注册这个指令

    import tableAutoScroll from './modules/tableAutoScroll.ts'
    const directives: any = {
      tableAutoScroll,
    }
    /**
     * @function 批量注册指令
     * @param app vue 实例对象
     */
    export const install = (app: any) => {
      Object.keys(directives).forEach((key) => {
        app.directive(key, directives[key]) // 将每个directive注册到app中
      })
    }
    

image-20241226224940418.png image-20241226225027524.png

我这边是将自己的弄了一个批量注册,正常使用就像官网里面注册指令就可以了

在需要滚动的el-table上使用这个指令就可以

image-20241226225257264.png

<!-- element 列表滚动指令插件 -->
<template>
  <div class="container">
    <el-table v-tableAutoScroll :data="tableData" height="300">
      <el-table-column prop="date" label="时间" />
      <el-table-column prop="name" label="名称" />
      <el-table-column prop="address" label="Address" />
    </el-table>
    <!-- delay:多少毫秒滚动一次 -->
    <el-table
      v-tableAutoScroll="{
        delay: 50,
      }"
      :data="tableData"
      height="300"
    >
      <el-table-column prop="date" label="时间" />
      <el-table-column prop="name" label="名称" />
      <el-table-column prop="address" label="Address" />
    </el-table>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
const tableData = ref<any>([])
onMounted(() => {
  tableData.value = Array.from(Array(100), (item, index) => ({
    date: '时间' + index,
    name: '名称' + index,
    address: '地点' + index,
  }))
  console.log('👉 ~ tableData.value=Array.from ~ tableData:', tableData)
})
</script>

<style lang="scss" scoped>
.container {
  height: 100%;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 100px;
  .el-table {
    width: 500px;
  }
}
</style>

上面这个例子,分别演示两种调用方法,带参数和不带参数

最后

做了这个工具之后,突然有很多思路,打算后面再做几个,做成一个开源项目,一个开源的vue3指令集