1. 方案一:新建scroll.tsx组件(通过监听滚动事件)

import React from "react";

namespace ScrollSpace {
  export type Props = {
    children?: React.ReactNode
    height?: string //高度
    load?: (data?: Event) => void //执行函数
    interval?: number //离底部的间隔内加载执行,默认20
    delay?: number //延迟时间,默认1000毫秒
  }

  export type Event = React.UIEvent<HTMLDivElement, UIEvent>
}

/* 滑动加载组件 */
export const Scroll: React.FC<ScrollSpace.Props> = (props) => {
  props = Object.assign({ interval: 20, load: () => { } }, props)
  return <div style={{ height: props.height, overflow: "auto" }} onScroll={debounce<ScrollSpace.Event>((data) => {
    let divEl = data.target as HTMLDivElement
    if (divEl.scrollTop + divEl.clientHeight + props.interval! > divEl.scrollHeight) {
      props.load!(data)
    }
  }, props.delay)}>
    {props.children}
  </div>
}

/* 防抖默认1秒 */
function debounce<T>(fn: (data: T) => void, delay: number = 1000) {
  let timeout: NodeJS.Timeout | null = null;
  return function (data: T) {
    if (timeout !== null) clearTimeout(timeout);
    timeout = setTimeout(fn.bind({}, data), delay);
  }
}
组件属性 类型 备注
children React.ReactNode 插槽
height string 高度
load Function(Event) 滑动到底部执行的函数
interval number 距离底部的间隔,默认20
delay number 函数执行的延迟时间,默认1000毫秒

1.2. 使用

import { Scroll } from "../Scroll/index"

function Index() {
  const [list,setList] = useState<React.ReactNode[]>([])

  /* 生成数据 */
  useEffect(()=>{
    setList(
      new Array(100).fill(null).map((_item, index) => {
        return <Col span={24} key={index}>【】【】【】【】【】】【】</Col>
      })
    )
  },[])

  return <Scroll height="100%" interval={500} load={(data) => {
      console.log("到底部了")
    }}>
    <Row>
      {list}
    </Row>
  </Scroll>
}

2. 方案二:新建scroll.tsx组件(通过观察者实现)

import React, { useEffect, useRef } from "react";

namespace ScrollSpace {
  export type Props = {
    children?: React.ReactNode
    height?: string //高度,默认100%
    load?: (data?: IntersectionObserverEntry) => void //执行函数
    isFirstLoad?: boolean //首次进入是否执行,默认true
  }
}

/* 滑动加载组件 */
export const Scroll: React.FC<ScrollSpace.Props> = (props) => {
  const loadingRef = useRef<HTMLSpanElement>(null)
  props = Object.assign({ load: () => { }, height: "100%", isFirstLoad: true }, props)

  useEffect(() => {
    let isFirst = props.isFirstLoad
    let ob = new IntersectionObserver(([entries]:IntersectionObserverEntry[]) => {
      if (entries.isIntersecting && isFirst) {
        props.load!(entries)
      }
      isFirst = true
    }, { threshold: 1 })
    ob.observe(loadingRef.current as HTMLSpanElement)
  }, [])

  return <div style={{ height: props.height, overflow: "auto" }}>
    {props.children}
    <span ref={loadingRef}>loading...</span>
  </div>
}
组件属性 类型 备注
children React.ReactNode 插槽
height string 高度
load Function(Event) 滑动到底部执行的函数
isFirstLoad boolean 首次进入是否执行,默认true

使用方法与方案一一样

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐