# How to Implement Infinite Scroll for Large Datasets Using the v-infinite-scroll Directive

> Effortlessly implement infinite scroll for large datasets with the Element UI v-infinite-scroll directive. Load more content seamlessly as users scroll, enhancing user experience and performance.

- Repository: [饿了么前端/element](https://github.com/ElemeFE/element)
- Tags: how-to-guide
- Published: 2026-03-07

---

**The Element UI `v-infinite-scroll` directive attaches to any scrollable container and executes a callback when the scroll position reaches a configurable distance from the bottom, making it ideal for paginating large datasets without external dependencies.**

The ElemeFE/element repository provides a lightweight, built-in solution for handling massive data lists through its **Infinite Scroll directive**. By attaching `v-infinite-scroll` to a container element, developers can implement efficient lazy loading with automatic throttling and distance-based triggers. This approach eliminates the need for heavy third-party libraries while providing fine-grained control over scroll behavior through native Vue.js directive hooks.

## Core Architecture and Source Implementation

The directive is implemented in [`packages/infinite-scroll/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/infinite-scroll/src/main.js) and registered globally through the Element UI entry point. It utilizes standard Vue directive hooks to manage event listeners and DOM calculations.

### Directive Lifecycle and Initialization

When the directive is bound to an element via the `inserted` hook, it performs several initialization steps defined in the source. First, it retrieves the scrollable parent container using `getScrollContainer(el)`. Then it parses directive attributes—including `delay`, `distance`, `disabled`, and `immediate`—through `getScrollOptions(el, vm)`.

The core scroll handler `handleScroll` is wrapped with a throttle function based on the `delay` attribute (defaulting to 200ms) to prevent excessive callback invocations. The directive stores these references on the element itself via `el[scope]` for cleanup purposes. If `immediate` is enabled, a `MutationObserver` watches for DOM changes inside the container to trigger an initial scroll check when content is insufficient to fill the viewport.

### Scroll Distance Calculation Logic

The `handleScroll` function in [`packages/infinite-scroll/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/infinite-scroll/src/main.js) (lines 89-118) implements dual calculation strategies depending on the container relationship. When the scroll container equals the target element, it compares `scrollTop + clientHeight` against `scrollHeight`. For nested containers where the element sits inside a scrolling parent, it calculates the element's offset relative to the container while factoring in border widths.

If the remaining scroll distance is less than or equal to the configured `distance` threshold, the user-supplied callback executes. The directive automatically disconnects any `MutationObserver` when scrolling should no longer trigger additional loads.

## Configuration Options for Performance Tuning

The directive exposes four key attributes that control how aggressively it triggers data fetching for large datasets.

### Throttling with delay

The `infinite-scroll-delay` attribute accepts a millisecond value that controls the throttle interval applied to scroll event listeners. According to the implementation in [`main.js`](https://github.com/ElemeFE/element/blob/main/main.js), the default 200ms interval prevents API flooding during rapid scroll gestures. For extremely heavy backend operations, increasing this to 300-500ms reduces server load while maintaining responsive UI feedback.

### Distance Thresholds

Setting `infinite-scroll-distance` to a positive pixel value (e.g., `150`) triggers the callback before the user reaches the absolute bottom of the container. This pre-fetching strategy ensures the next page of data arrives and renders while the user is still scrolling, eliminating perceived latency in large dataset navigation.

### Immediate Execution and Disabled States

The `infinite-scroll-immediate` boolean triggers the callback immediately upon directive insertion, ensuring the first data page loads even when the container initially appears empty. Meanwhile, `infinite-scroll-disabled` accepts a boolean expression that temporarily halts scroll monitoring—critical for preventing concurrent API requests while a previous batch is still loading.

## Implementation Examples

### Basic Static Data Implementation

For datasets that load from local state or memory, attach the directive to any element with explicit height and overflow properties:

```vue
<template>
  <ul class="infinite-list" v-infinite-scroll="load" style="height: 300px; overflow: auto;">
    <li v-for="item in items" :key="item.id" class="infinite-list-item">
      {{ item.name }}
    </li>
  </ul>
</template>

<script>
export default {
  data () {
    return {
      items: [],
      page: 1,
    };
  },
  created () {
    this.load();
  },
  methods: {
    load () {
      setTimeout(() => {
        const newItems = Array.from({ length: 20 }, (_, i) => ({
          id: (this.page - 1) * 20 + i,
          name: `Item ${(this.page - 1) * 20 + i + 1}`
        }));
        this.items.push(...newItems);
        this.page += 1;
      }, 500);
    }
  }
};
</script>

```

### Large Dataset with API Pagination

For production applications consuming remote APIs, combine the directive with loading states and conditional disabling:

```vue
<template>
  <div class="list-wrapper" style="height: 500px; overflow:auto;">
    <ul class="list" v-infinite-scroll="loadMore"
        :infinite-scroll-disabled="loading || noMore"
        infinite-scroll-distance="150"
        infinite-scroll-delay="300"
        infinite-scroll-immediate>
      <li v-for="post in posts" :key="post.id" class="list-item">
        {{ post.title }}
      </li>
    </ul>
    <p v-if="loading">Loading more…</p>
    <p v-else-if="noMore">No more results.</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      posts: [],
      page: 1,
      pageSize: 30,
      loading: false,
    };
  },
  computed: {
    noMore () {
      return this.posts.length && this.posts.length % this.pageSize !== 0;
    }
  },
  methods: {
    async loadMore () {
      if (this.loading) return;
      this.loading = true;
      try {
        const res = await fetch(
          `https://api.example.com/posts?page=${this.page}&size=${this.pageSize}`
        );
        const data = await res.json();
        this.posts.push(...data.items);
        this.page += 1;
      } finally {
        this.loading = false;
      }
    }
  }
};
</script>

```

## Key Source Files and Type Definitions

Understanding the implementation details requires referencing specific files in the ElemeFE/element repository:

- **[`packages/infinite-scroll/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/infinite-scroll/src/main.js)**: Contains the complete directive implementation including the `inserted` and `unbind` hooks, throttle logic, and `handleScroll` distance calculations.
- **[`types/infinite-scroll.d.ts`](https://github.com/ElemeFE/element/blob/main/types/infinite-scroll.d.ts)**: Provides TypeScript definitions confirming the directive expects a function as its bound value.
- **[`examples/docs/en-US/infiniteScroll.md`](https://github.com/ElemeFE/element/blob/main/examples/docs/en-US/infiniteScroll.md)**: Official documentation covering attribute references and usage patterns.
- **[`test/unit/specs/infiniteScroll.spec.js`](https://github.com/ElemeFE/element/blob/main/test/unit/specs/infiniteScroll.spec.js)**: Unit tests verifying scroll triggering thresholds and MutationObserver behavior.

## Summary

- The **`v-infinite-scroll`** directive in Element UI provides native Vue.js infinite scrolling without external dependencies.
- Source code in [`packages/infinite-scroll/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/infinite-scroll/src/main.js) implements throttled scroll listeners and dual-mode distance calculations for both element and container scrolling scenarios.
- **Four key attributes** control behavior: `delay` (throttling), `distance` (pre-fetch threshold), `immediate` (initial load), and `disabled` (conditional halting).
- The directive automatically cleans up event listeners via the `unbind` hook, preventing memory leaks in single-page applications.
- For large datasets, combine `infinite-scroll-distance` with `infinite-scroll-disabled` to implement efficient pagination that loads data before the user reaches the bottom while preventing concurrent requests.

## Frequently Asked Questions

### How does the v-infinite-scroll directive calculate when to trigger the load callback?

According to the source code in [`packages/infinite-scroll/src/main.js`](https://github.com/ElemeFE/element/blob/main/packages/infinite-scroll/src/main.js), the `handleScroll` function uses two calculation strategies. If the scroll container is the element itself, it compares `scrollTop + clientHeight` against `scrollHeight`. For nested containers, it measures the element's offset relative to the scrolling parent while accounting for border widths. When the remaining distance is less than or equal to the `infinite-scroll-distance` value, the callback executes.

### What is the default throttle delay and how can I adjust it for high-traffic APIs?

The default delay is **200 milliseconds**, implemented via a throttle wrapper around the scroll handler in the `inserted` hook. To reduce server load for high-traffic APIs, increase the `infinite-scroll-delay` attribute to 300-500ms. This value is passed directly to the throttle function defined in the directive's source.

### How do I prevent the infinite scroll from triggering multiple simultaneous API requests?

Bind a boolean expression to the `infinite-scroll-disabled` attribute that evaluates to `true` while your request is in flight. Typically, this involves setting a `loading` flag to `true` at the start of your callback method and `false` upon completion. The directive checks this disabled state inside `handleScroll` before invoking your function, effectively debouncing at the application level.

### Can I use v-infinite-scroll with TypeScript projects?

Yes. The repository includes TypeScript definitions in [`types/infinite-scroll.d.ts`](https://github.com/ElemeFE/element/blob/main/types/infinite-scroll.d.ts) that specify the directive value must be a function. When using Vue with TypeScript, ensure your load method is properly typed as a function reference to satisfy the compiler checks defined in the Element UI type system.