You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JavaScript实现网站滚动加载内容?

实现页面滚动加载内容的方法

核心原理

滚动加载(又称无限滚动)的核心逻辑是:当用户滚动页面到接近底部的位置时,自动发起请求获取新数据,再将数据追加到页面内容末尾。

原生JavaScript实现方案

方案1:使用IntersectionObserver(推荐,性能更优)

这是浏览器原生提供的API,专门用于监听元素是否进入视口,无需频繁监听滚动事件,性能表现更好。

  1. 在页面内容最底部添加一个触发加载的占位元素:
<div id="loadTrigger" style="height: 20px; margin-top: 20px;"></div>
  1. 编写JavaScript逻辑:
let isLoading = false;
const loadTrigger = document.getElementById('loadTrigger');

// 创建观察者实例
const observer = new IntersectionObserver((entries) => {
  const entry = entries[0];
  // 当触发元素进入视口且当前未加载时,执行加载
  if (entry.isIntersecting && !isLoading) {
    isLoading = true;
    // 模拟异步请求数据
    fetchNewData().then(newItems => {
      renderItems(newItems); // 将新数据渲染到页面
      isLoading = false;
      // 若无更多数据,停止监听
      if (hasNoMoreData()) {
        observer.unobserve(loadTrigger);
      }
    });
  }
}, { threshold: 0.1 }); // 元素进入视口10%时触发

// 开始监听触发元素
observer.observe(loadTrigger);

// 模拟数据请求和渲染函数
function fetchNewData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve([`新内容${Date.now()}`, `新内容${Date.now()+1}`]);
    }, 1000);
  });
}

function renderItems(items) {
  const list = document.getElementById('contentList');
  items.forEach(item => {
    const li = document.createElement('li');
    li.textContent = item;
    list.appendChild(li);
  });
}

function hasNoMoreData() {
  // 根据实际业务逻辑判断是否还有更多数据,比如总页数是否加载完毕
  return false;
}

方案2:监听scroll事件(传统方式)

通过监听窗口滚动事件,计算滚动位置判断是否需要加载数据,注意要加防抖避免频繁触发。

let isLoading = false;
let page = 1;
const loadThreshold = 100; // 距离底部100px时触发加载

// 防抖函数
function debounce(fn, delay) {
  let timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, arguments), delay);
  };
}

// 滚动监听逻辑
const handleScroll = debounce(() => {
  const windowHeight = window.innerHeight;
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  const documentHeight = document.documentElement.scrollHeight;

  // 判断是否到达加载阈值
  if (scrollTop + windowHeight >= documentHeight - loadThreshold && !isLoading) {
    isLoading = true;
    page++;
    // 请求数据
    fetch(`/api/data?page=${page}`).then(res => res.json()).then(data => {
      renderItems(data.items);
      isLoading = false;
      // 无更多数据时移除监听
      if (data.hasMore === false) {
        window.removeEventListener('scroll', handleScroll);
      }
    });
  }
}, 200); // 200ms防抖延迟

window.addEventListener('scroll', handleScroll);

框架中的实现示例(以React为例)

在React中可以封装自定义Hook来实现IntersectionObserver的监听:

import { useEffect, useRef, useState } from 'react';

function useInView(options = {}) {
  const ref = useRef(null);
  const [isInView, setIsInView] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIsInView(entry.isIntersecting);
    }, options);

    const currentRef = ref.current;
    if (currentRef) observer.observe(currentRef);

    return () => {
      if (currentRef) observer.unobserve(currentRef);
    };
  }, [options]);

  return [ref, isInView];
}

function InfiniteScrollList() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [isLoading, setIsLoading] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [triggerRef, isTriggerInView] = useInView({ threshold: 0.1 });

  useEffect(() => {
    if (isTriggerInView && !isLoading && hasMore) {
      setIsLoading(true);
      // 模拟请求数据
      setTimeout(() => {
        const newItems = Array.from({length: 10}, (_, i) => `Item ${(page-1)*10 + i + 1}`);
        setItems(prev => [...prev, ...newItems]);
        setPage(prev => prev + 1);
        setIsLoading(false);
        // 模拟加载3页后无更多数据
        if (page >= 3) setHasMore(false);
      }, 1000);
    }
  }, [isTriggerInView, isLoading, hasMore, page]);

  return (
    <div>
      <ul>
        {items.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
      {isLoading && <div>加载中...</div>}
      {hasMore && <div ref={triggerRef} style={{height: '20px'}}></div>}
      {!hasMore && <div>已加载全部内容</div>}
    </div>
  );
}

关键注意事项

  • 避免重复请求:必须设置isLoading状态,在请求未完成时不触发新的加载逻辑。
  • 性能优化:优先使用IntersectionObserver,相比scroll事件能减少不必要的计算和触发;传统scroll事件一定要加防抖。
  • 无更多数据处理:当数据加载完毕后,要停止监听滚动事件或取消IntersectionObserver的观察,避免无效触发。
  • 兼容处理:如果需要兼容旧浏览器,可给IntersectionObserver添加polyfill。

内容的提问来源于stack exchange,提问作者Sadam khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:25:13