0.2.1 • Published 7 months ago

@seamless-scroll/vue v0.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

@seamless-scroll/vue

Vue 3 无缝滚动组件,基于 Composition API 构建。

npm version License: ISC Vue

介绍

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

安装

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

组件用法

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

基本用法

<script setup>
import { ref } from "vue";
import { SeamlessScroll } from "@seamless-scroll/vue";

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

const handleItemClick = (item) => {
  console.log("点击了项目:", item);
};
</script>
<template>
  <SeamlessScroll
    :data="items"
    direction="vertical"
    :speed="60"
    :item-size="50"
    @item-click="handleItemClick"
  >
    <template #default="{ item }">
      <div class="scroll-item">{{ item.text }}</div>
    </template>
  </SeamlessScroll>
</template>

使用泛型(类型安全)

<script setup lang="ts">
import { ref } from "vue";
import { SeamlessScroll } from "@seamless-scroll/vue";

interface Announcement {
  id: number;
  text: string;
  date: string;
}

// 使用泛型指定数据类型
const items = ref<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}`);
};
</script>
<template>
  <SeamlessScroll
    :data="items"
    direction="vertical"
    :speed="60"
    :item-size="50"
    @item-click="handleItemClick"
  >
    <!-- TypeScript 会自动推断 item 为 Announcement 类型 -->
    <template #default="{ item }">
      <div class="scroll-item">
        <div>{{ item.text }}</div>
        <div class="date">{{ item.date }}</div>
      </div>
    </template>
  </SeamlessScroll>
</template>

水平滚动

<template>
  <SeamlessScroll :data="items" direction="horizontal" :speed="40" :item-size="50">
    <template #default="{ item }">
      <div class="scroll-item">{{ item.text }}</div>
    </template>
  </SeamlessScroll>
</template>

配置多个选项

<template>
  <SeamlessScroll
    :data="items"
    direction="vertical"
    :speed="50"
    :item-size="50"
    :hoverPause="true"
    :pauseTime="1000"
    :duration="500"
    :autoScroll="true"
    :forceScrolling="false"
  >
    <template #default="{ item }">
      <div class="scroll-item">{{ item.text }}</div>
    </template>
  </SeamlessScroll>
</template>

API 文档

组件 Props

属性类型默认值描述
dataT[][]要展示的数据列表(支持泛型类型T)
direction'vertical' | 'horizontal''vertical'滚动方向
speednumber50滚动速度(像素/秒)
durationnumber500每次滚动动画的持续时间(毫秒)
pauseTimenumber2000每次滚动后的暂停时间(毫秒)
hoverPausebooleantrue是否在鼠标悬停时暂停
autoScrollbooleantrue是否自动开始滚动
forceScrollingbooleanfalse是否强制滚动(即使内容未超出容器)
containerHeightstring \| number'100%'容器高度
containerWidthstring \| number'100%'容器宽度
customClassstring-自定义CSS类名
styleCSSProperties-自定义样式
itemSizenumber-固定项目尺寸(像素),用于虚拟滚动计算
minItemSizenumber-最小项目尺寸(像素),用于变高度虚拟滚动
virtualScrollBuffernumber5虚拟滚动缓冲区大小,值越大,滚动越平滑,但渲染项目更多
itemKeystring \| ((item: T, index: number) => string \| number)-项目键名或生成函数,用于列表项的唯一标识

组件事件

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

组件插槽

插槽名插槽参数描述
default{ item: T, index: number }列表项的渲染插槽
empty无数据时的插槽

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;
}): {
  containerRef: Ref<HTMLElement | null>;
  contentRef: Ref<HTMLElement | null>;
  realListRef: Ref<HTMLElement | null>;
  state: Readonly<ScrollState>;
  methods: ScrollMethods;
  getVirtualItems: (data: T[]) => VirtualScrollItem<T>[];
};

返回值

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

属性类型描述
isScrollingboolean是否正在滚动
isPausedboolean是否暂停
isHoveringboolean鼠标是否悬停
isScrollNeededboolean是否需要滚动
scrollDistancenumber滚动距离
containerSizenumber容器尺寸
contentSizenumber内容尺寸
minClonesnumber最小克隆数量
isVirtualizedboolean是否启用虚拟滚动
startIndexnumber虚拟滚动起始索引
endIndexnumber虚拟滚动结束索引
averageSizenumber平均项目尺寸

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

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

高级用法

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

<script setup lang="ts">
import { ref } from "vue";
import { SeamlessScroll } from "@seamless-scroll/vue";

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

// SeamlessScroll 组件会自动根据传入的 data 推断类型
const products = ref<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}`);
};
</script>

<template>
  <SeamlessScroll :data="products" direction="horizontal" :speed="40" @item-click="handleItemClick">
    <!-- item 会有完整的类型提示 -->
    <template #default="{ item, index }">
      <div class="product-card">
        <img :src="item.imageUrl" :alt="item.name" />
        <h3>{{ item.name }}</h3>
        <p>¥{{ item.price }}</p>
      </div>
    </template>
  </SeamlessScroll>
</template>

控制组件实例

<template>
  <SeamlessScroll ref="scrollRef" :data="items">
    <template #default="{ item }">
      <div class="scroll-item">{{ item.text }}</div>
    </template>
  </SeamlessScroll>
  <button @click="controlScroll('start')">开始</button>
  <button @click="controlScroll('stop')">停止</button>
</template>

<script setup>
import { ref } from "vue";
import { SeamlessScroll } from "@seamless-scroll/vue";

const scrollRef = ref(null);

function controlScroll(action) {
  if (scrollRef.value) {
    scrollRef.value[action]();
  }
}
</script>

虚拟滚动

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

如何使用虚拟滚动

虚拟滚动有两种模式:

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

  <!-- 动态高度虚拟滚动 -->
  <SeamlessScroll :data="mixedHeightData" :minItemSize="50" :virtualScrollBuffer="10">
    <template #default="{ item }">
      <div class="item" :style="{ height: item.height + 'px' }">
        {{ item.content }}
      </div>
    </template>
  </SeamlessScroll>
</template>

性能优化

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

  1. 实时测量每个显示项的实际高度
  2. 记录每种类型项目的平均高度(如果项目有 type 属性)
  3. 智能预测尚未渲染项目的高度
  4. 使用二分查找算法快速定位滚动位置
<script setup lang="ts">
interface Card {
  id: number;
  type: "small" | "medium" | "large"; // 组件会自动统计不同type的平均高度
  content: string;
}

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

<template>
  <SeamlessScroll :data="cards" :minItemSize="50" itemKey="id">
    <template #default="{ item }">
      <div class="card" :class="item.type">
        {{ item.content }}
      </div>
    </template>
  </SeamlessScroll>
</template>

许可证

ISC

0.2.1

7 months ago

0.2.0

8 months ago

0.1.2

8 months ago

0.1.1

8 months ago

0.1.0

8 months ago