npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@seamless-scroll/react

v0.2.1

Published

React component for seamless scrolling

Downloads

13

Readme

@seamless-scroll/react

React 无缝滚动组件,提供高性能的内容滚动体验。

npm version License: MIT React

介绍

@seamless-scroll/react 提供了一个易用的 React 组件和 Hook,用于实现无缝滚动效果。适用于公告、列表、轮播等场景。

安装

npm install @seamless-scroll/react
# 或
pnpm add @seamless-scroll/react
# 或
yarn add @seamless-scroll/react

组件用法

更多内容可以查看Github上的examples。

基本用法

import { useState } from "react";
import { SeamlessScroll } from "@seamless-scroll/react";

function App() {
  const [items, setItems] = useState([
    { id: 1, text: "公告1" },
    { id: 2, text: "公告2" },
    { id: 3, text: "公告3" },
  ]);

  const handleItemClick = (item) => {
    console.log("点击了项目:", item);
  };

  return (
    <SeamlessScroll data={items} direction="vertical" speed={60} onItemClick={handleItemClick} />
  );
}

export default App;

使用泛型(类型安全)

import { useState } from "react";
import { SeamlessScroll } from "@seamless-scroll/react";

// 定义数据类型
interface Announcement {
  id: number;
  text: string;
  date: string;
}

function App() {
  // 使用泛型指定数据类型
  const [items, setItems] = useState<Announcement[]>([
    { id: 1, text: "公告1", date: "2023-01-01" },
    { id: 2, text: "公告2", date: "2023-01-02" },
    { id: 3, text: "公告3", date: "2023-01-03" },
  ]);

  // 自动推断 item 为 Announcement 类型
  const handleItemClick = (item: Announcement) => {
    console.log(`点击了公告: ${item.text}, 日期: ${item.date}`);
  };

  return (
    <SeamlessScroll data={items} direction="vertical" speed={60} onItemClick={handleItemClick}>
      {/* TypeScript 会自动推断 item 为 Announcement 类型 */}
      {(item, index) => (
        <div className="announcement">
          <div>{item.text}</div>
          <div className="date">{item.date}</div>
        </div>
      )}
    </SeamlessScroll>
  );
}

export default App;

水平滚动

<SeamlessScroll data={items} direction="horizontal" speed={40} />

虚拟滚动

SeamlessScroll 组件支持虚拟滚动,特别适用于大数据量渲染场景。当列表项较多时(通常超过 50 项),组件会自动启用虚拟滚动,仅渲染可见区域内的项目,显著提升渲染性能。

如何使用虚拟滚动

虚拟滚动有两种模式:

  1. 固定高度模式:设置 itemSize 属性,每个项的高度相同
  2. 动态高度模式:不设置 itemSize,但需要设置 minItemSize,组件会动态测量并记忆每个项的实际高度
// 固定高度虚拟滚动
<SeamlessScroll data={largeDataset} itemSize={80} virtualScrollBuffer={8}>
  {(item) => (
    <div className="item">{item.content}</div>
  )}
</SeamlessScroll>

// 动态高度虚拟滚动
<SeamlessScroll data={mixedHeightData} minItemSize={50} virtualScrollBuffer={10}>
  {(item) => (
    <div className="item" style={{ height: item.height + 'px' }}>
      {item.content}
    </div>
  )}
</SeamlessScroll>

性能优化

对于动态高度模式,组件会:

  1. 实时测量每个显示项的实际高度
  2. 记录每种类型项目的平均高度(如果项目有 type 属性)
  3. 智能预测尚未渲染项目的高度
  4. 使用二分查找算法快速定位滚动位置
import { useState } from "react";
import { SeamlessScroll } from "@seamless-scroll/react";

interface Card {
  id: number;
  type: "small" | "medium" | "large"; // 组件会自动统计不同type的平均高度
  content: string;
}

function App() {
  const [cards, setCards] = useState<Card[]>([
    { id: 1, type: "small", content: "小卡片" },
    { id: 2, type: "medium", content: "中等卡片内容较多" },
    { id: 3, type: "large", content: "大卡片有很多内容..." },
    // ... 更多数据
  ]);

  return (
    <SeamlessScroll data={cards} minItemSize={50} itemKey="id">
      {(item) => <div className={`card ${item.type}`}>{item.content}</div>}
    </SeamlessScroll>
  );
}

export default App;

API 文档

组件 Props

| 属性 | 类型 | 默认值 | 描述 | | --------------------- | ---------------------------------------------------------- | ------------ | ------------------------------------------------------ | | data | T[] | [] | 要展示的数据列表(支持泛型类型T) | | direction | 'vertical' | 'horizontal' | 'vertical' | 滚动方向 | | speed | number | 50 | 滚动速度(像素/秒) | | duration | number | 500 | 每次滚动动画的持续时间(毫秒) | | pauseTime | number | 2000 | 每次滚动后的暂停时间(毫秒) | | hoverPause | boolean | true | 是否在鼠标悬停时暂停 | | autoScroll | boolean | true | 是否自动开始滚动 | | forceScrolling | boolean | false | 是否强制滚动(即使内容未超出容器) | | containerHeight | string \| number | '100%' | 容器高度 | | containerWidth | string \| number | '100%' | 容器宽度 | | customClass | string | - | 自定义CSS类名 | | style | CSSProperties | - | 自定义样式 | | itemSize | number | - | 固定项目尺寸(像素),用于虚拟滚动计算 | | minItemSize | number | - | 最小项目尺寸(像素),用于变高度虚拟滚动 | | virtualScrollBuffer | number | 5 | 虚拟滚动缓冲区大小,值越大,滚动越平滑,但渲染项目更多 | | itemKey | string \| ((item: T, index: number) => string \| number) | - | 项目键名或生成函数,用于列表项的唯一标识 | | emptyRender | ReactNode | "无数据" | 无数据时显示的内容 |

组件事件

| 事件名 | 参数 | 描述 | | ------------- | -------------------------- | ---------------- | | onItemClick | (item: T, index: number) | 点击列表项时触发 |

自定义渲染

React组件支持以下方式自定义内容渲染:

| 渲染方式 | 描述 | | ---------- | --------------------------------------- | | 函数子组件 | 通过函数定制每项的渲染 | | 克隆组件 | 将props注入到子组件 | | 默认渲染 | 使用JSON.stringify渲染 | | 无数据渲染 | 通过emptyRender属性自定义无数据时的内容 |

函数子组件示例

<SeamlessScroll data={items}>
  {(item, index) => (
    <div className="custom-item" key={index}>
      <span className="title">{item.title}</span>
      <span className="desc">{item.desc}</span>
    </div>
  )}
</SeamlessScroll>

克隆组件示例

// 创建一个自定义项组件
const ListItem = ({ item, index }) => (
  <div className="list-item">
    <span className="index">{index + 1}.</span>
    <span className="content">{item.text}</span>
  </div>
);

// 在SeamlessScroll中使用
<SeamlessScroll data={items}>
  <ListItem />
</SeamlessScroll>;

无数据渲染示例

// 自定义空状态显示
<SeamlessScroll
  data={[]}
  emptyRender={
    <div className="empty-state">
      <img src="/empty.svg" alt="暂无数据" />
      <p>暂无公告,请稍后查看</p>
    </div>
  }
/>

useSeamlessScroll Hook

参数

function useSeamlessScroll<T>(props: {
  dataTotal: number;
  direction?: "vertical" | "horizontal";
  speed?: number;
  duration?: number;
  pauseTime?: number;
  hoverPause?: boolean;
  autoScroll?: boolean;
  forceScrolling?: boolean;
  itemSize?: number;
  minItemSize?: number;
  virtualScrollBuffer?: number;
  onScroll?: (distance: number, direction: string) => void;
  onItemClick?: (item: T, index: number) => void;
  customClass?: string;
  style?: React.CSSProperties;
}): {
  containerRef: React.RefObject<HTMLDivElement>;
  contentRef: React.RefObject<HTMLDivElement>;
  realListRef: React.RefObject<HTMLDivElement>;
  state: Readonly<ScrollState>;
  methods: ScrollMethods;
  getVirtualItems: (data: T[]) => VirtualScrollItem<T>[];
  styles: () => ReactSeamlessScrollStyles;
};

返回值

state - 滚动状态对象,包含以下属性:

| 属性 | 类型 | 描述 | | -------------------- | ---------- | ------------------ | | isScrolling | boolean | 是否正在滚动 | | isPaused | boolean | 是否暂停 | | isHovering | boolean | 鼠标是否悬停 | | scrollDistance | number | 滚动距离 | | contentSize | number | 内容尺寸 | | containerSize | number | 容器尺寸 | | isScrollNeeded | boolean | 是否需要滚动 | | minClones | number | 最小克隆数量 | | isVirtualized | boolean | 是否启用虚拟滚动 | | startIndex | number | 虚拟滚动起始索引 | | endIndex | number | 虚拟滚动结束索引 | | averageSize | number | 平均项目尺寸 | | itemSizeList | number[] | 项目尺寸缓存列表 | | totalMeasuredItems | number | , 已测量的项目数量 |

methods - 控制方法对象,包含以下方法:

| 方法 | 描述 | | ------------------------ | ------------------ | | start() | 开始滚动 | | stop() | 停止滚动 | | pause() | 暂停滚动 | | resume() | 恢复滚动 | | reset() | 重置滚动位置 | | forceScroll() | 强制开始滚动 | | updateSize() | 更新尺寸计算 | | updateOptions(options) | 更新配置参数 | | updateItemSizeList() | 更新指定项目的尺寸 | | predictItemSize() | 预测指定项目的尺寸 | | getVirtualCloneRange() | 获取虚拟克隆范围 |

高级用法

使用 TypeScript 泛型提升类型安全性

import { useState, useRef } from "react";
import { SeamlessScroll } from "@seamless-scroll/react";

// 定义您的数据类型
interface Product {
  id: number;
  name: string;
  price: number;
  imageUrl: string;
}

function App() {
  // SeamlessScroll 组件会自动根据传入的 data 推断类型
  const [products, setProducts] = useState<Product[]>([
    { id: 1, name: "商品1", price: 199, imageUrl: "/img/1.jpg" },
    { id: 2, name: "商品2", price: 299, imageUrl: "/img/2.jpg" },
    { id: 3, name: "商品3", price: 399, imageUrl: "/img/3.jpg" },
  ]);

  // item 会被推断为 Product 类型
  const handleItemClick = (item: Product, index: number) => {
    console.log(`点击了商品: ${item.name}, 价格: ${item.price}`);
  };

  return (
    <SeamlessScroll data={products} direction="horizontal" speed={40} onItemClick={handleItemClick}>
      {/* item 会有完整的类型提示 */}
      {(item, index) => (
        <div className="product-card">
          <img src={item.imageUrl} alt={item.name} />
          <h3>{item.name}</h3>
          <p>¥{item.price}</p>
        </div>
      )}
    </SeamlessScroll>
  );
}

export default App;

控制组件实例

import { useRef } from "react";
import { SeamlessScroll } from "@seamless-scroll/react";

function App() {
  const scrollRef = useRef(null);
  const items = [
    { id: 1, text: "项目1" },
    { id: 2, text: "项目2" },
    { id: 3, text: "项目3" },
  ];

  function controlScroll(action) {
    if (scrollRef.current) {
      scrollRef.current[action]();
    }
  }

  return (
    <>
      <SeamlessScroll ref={scrollRef} data={items}>
        {(item) => <div className="scroll-item">{item.text}</div>}
      </SeamlessScroll>
      <button onClick={() => controlScroll("start")}>开始</button>
      <button onClick={() => controlScroll("stop")}>停止</button>
    </>
  );
}

export default App;

许可证

MIT