How to Build a Custom Vue3 Auto‑Scrolling Table Directive with Element‑Plus

This article explains how to create a custom Vue 3 directive for automatic scrolling of Element‑Plus tables, covering the underlying logic, handling mouse events, conditional scrolling, and integration steps with code examples, enabling developers to implement smooth list carousels without third‑party plugins.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
How to Build a Custom Vue3 Auto‑Scrolling Table Directive with Element‑Plus

Introduction

This tool is a Vue3 directive designed for the Element‑Plus UI library; it assumes a basic understanding of Vue3 directives.

Demo

Demo GIF
Demo GIF

Implementation Idea

First determine the required features:

Automatic list scrolling

Pause on mouse hover

Resume on mouse leave

Continue scrolling from the current position after wheel scroll completes

Do not scroll when the number of items is below a certain threshold

Scrolling Logic

By inspecting the el-table structure, the el-scrollbar__view contains all items, while el-scrollbar__wrap is a fixed‑height container. The directive obtains the el-scrollbar__wrap element, sets a timer, and repeatedly updates its scrollTop value, storing the value in a variable to keep it persistent.

Pause/Resume Logic

A boolean variable is used inside the timer; when the variable is true the scroll proceeds, otherwise it stops.

Wheel Event Logic

When the mouse leaves the list, the current scrollTop of el-scrollbar__wrap is saved to the variable so the timer can continue scrolling from that position.

Non‑Scrolling Logic

The directive compares the height of el-scrollbar__view with the height of el-scrollbar__wrap; scrolling only occurs when the content height exceeds the container height.

Source Code

File:

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);
    }
    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;
    });
  },
};

The created hook initializes three variables: a timer reference, a scroll‑enabled flag, and the current scroll position. The mounted hook reads an optional delay option to customize the scroll speed.

Usage

Place the directive file in your project.

Register the directive in main.ts and optionally expose an install function for batch registration.

import tableAutoScroll from './modules/tableAutoScroll.ts';
const directives: any = { tableAutoScroll };
export const install = (app: any) => {
  Object.keys(directives).forEach(key => {
    app.directive(key, directives[key]);
  });
};

Apply the directive to an el-table:

<!-- element list scroll directive plugin -->
<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: milliseconds per scroll -->
    <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), (_, index) => ({
    date: '时间' + index,
    name: '名称' + index,
    address: '地点' + index,
  }));
});
</script>

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

The example demonstrates both parameter‑less and parameterized usage.

Conclusion

After building this tool, the author plans to develop additional Vue3 directives and publish them as an open‑source directive collection.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendVue3Element PlusDirectiveAuto-Scroll
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.