快速开始

reelkit 是一个单条目滑动器 —— 同一时间只显示一个条目,就像 TikTok、Instagram Reels 或 Stories。非常适合竖向视频流、全屏画廊和可滑动的内容。

喜欢 ReelKit 吗?

如果 ReelKit 对你有帮助,欢迎在 GitHub 上点个 Star。这能让更多开发者发现这个项目,也能支持它持续发展。谢谢你,真心感谢你的支持!

0.x.x —— API 尚未稳定

ReelKit 正在活跃开发中。在 0.x.x 期间,API 可能在次版本之间发生变化,且不保证有废弃过渡期。 请锁定版本号,避免意外的破坏性变更。

选择你的框架

在线试用

直接在浏览器里试,无需安装:

快速上手

用 React 写一个最小的竖向滑动器:

tsx
import { Reel, ReelIndicator } from '@reelkit/react';

const items = [
  { id: 1, title: 'Slide 1', color: '#6366f1' },
  { id: 2, title: 'Slide 2', color: '#8b5cf6' },
  { id: 3, title: 'Slide 3', color: '#ec4899' },
];

function App() {
  return (
    <Reel
      count={items.length}
      size={[400, 600]}
      direction="vertical"
      enableWheel
      itemBuilder={(index) => (
        <div
          style={{
            width: '100%',
            height: '100%',
            background: items[index].color,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            fontSize: '2rem',
            color: 'white',
          }}
        >
          {items[index].title}
        </div>
      )}
    >
      <ReelIndicator />
    </Reel>
  );
}

快速上手

用 Angular 写一个最小的竖向滑动器:

typescript
import { Component } from '@angular/core';
import {
  ReelComponent,
  ReelIndicatorComponent,
  RkReelItemDirective,
} from '@reelkit/angular';

const items = [
  { id: 1, title: 'Slide 1', color: '#6366f1' },
  { id: 2, title: 'Slide 2', color: '#8b5cf6' },
  { id: 3, title: 'Slide 3', color: '#ec4899' },
];

@Component({
  standalone: true,
  imports: [ReelComponent, ReelIndicatorComponent, RkReelItemDirective],
  template: `
    <rk-reel [count]="items.length" [size]="[400, 600]"
             direction="vertical" [enableWheel]="true">
      <ng-template rkReelItem let-i let-size="size">
        <div [style.width.px]="size[0]" [style.height.px]="size[1]"
             [style.background]="items[i].color"
             style="display:flex;align-items:center;justify-content:center;
                    font-size:2rem;color:#fff">
          {{ items[i].title }}
        </div>
      </ng-template>
      <rk-reel-indicator />
    </rk-reel>
  `,
})
export class AppComponent {
  readonly items = items;
}

快速上手

用 Vue 写一个最小的竖向滑动器:

vue
<script setup lang="ts">
import { Reel, ReelIndicator } from '@reelkit/vue';

const items = [
  { id: 1, title: 'Slide 1', color: '#6366f1' },
  { id: 2, title: 'Slide 2', color: '#8b5cf6' },
  { id: 3, title: 'Slide 3', color: '#ec4899' },
];
</script>

<template>
  <Reel
    :count="items.length"
    :size="[400, 600]"
    direction="vertical"
    enable-wheel
  >
    <template #item="{ index, size }">
      <div
        :style="{
          width: size[0] + 'px',
          height: size[1] + 'px',
          background: items[index].color,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: '2rem',
          color: '#fff',
        }"
      >
        {{ items[index].title }}
      </div>
    </template>

    <ReelIndicator />
  </Reel>
</template>

核心概念

Reel

Reel 组件是主容器,负责管理滑动器状态、处理触摸手势、键盘导航和动画。 它通过 itemBuilder 这一 render prop 模式来渲染幻灯片。

itemBuilder

itemBuilder 属性是一个函数,接收索引并返回该幻灯片的内容。 正是这个模式让虚拟化成为可能 —— 只有可见的条目会被渲染。

ReelIndicator

可选组件,显示 Instagram 风格的进度指示器,标出当前在滑动器中的位置。

tsx
import { Reel, ReelIndicator } from '@reelkit/react';

function App() {
  return (
    <Reel
      count={items.length}
      size={[400, 600]}
      itemBuilder={(index) => <Slide data={items[index]} />}
    >
      <ReelIndicator />
    </Reel>
  );
}
html
<rk-reel [count]="items.length" [size]="[400, 600]">
  <ng-template rkReelItem let-index>
    <app-slide [data]="items[index]" />
  </ng-template>
  <rk-reel-indicator />
</rk-reel>
vue-html
<Reel :count="items.length" :size="[400, 600]">
  <template #item="{ index }">
    <Slide :data="items[index]" />
  </template>
  <ReelIndicator />
</Reel>

内置的导航方式:

  • 触摸 / 滑动: 拖动即可翻页,带惯性和吸附
  • 键盘: 方向键(浮层组件还会处理 Escape 关闭)
  • 鼠标滚轮: 用 enableWheel 属性开启
  • 编程式: 通过 apiRef 调用 next()、 prev()、 goTo()
tsx
import { useRef } from 'react';
import { Reel, type ReelApi } from '@reelkit/react';

function App() {
  const apiRef = useRef<ReelApi>(null);

  return (
    <>
      <Reel
        count={10}
        size={[400, 600]}
        apiRef={apiRef}
        itemBuilder={(index) => <Slide index={index} />}
      />
      <button onClick={() => apiRef.current?.prev()}>Prev</button>
      <button onClick={() => apiRef.current?.next()}>Next</button>
      <button onClick={() => apiRef.current?.goTo(5)}>Go to 5</button>
    </>
  );
}
html
<rk-reel
  [count]="10"
  [size]="[400, 600]"
  (apiReady)="reelApi = $event"
>
  <ng-template rkReelItem let-index>
    <app-slide [index]="index" />
  </ng-template>
</rk-reel>

<button (click)="reelApi?.prev()">Prev</button>
<button (click)="reelApi?.next()">Next</button>
<button (click)="reelApi?.goTo(5)">Go to 5</button>
vue
<script setup lang="ts">
import { ref } from 'vue';
import { Reel, type ReelExpose } from '@reelkit/vue';

const reelRef = ref<InstanceType<typeof Reel> & ReelExpose>();
</script>

<template>
  <Reel ref="reelRef" :count="10" :size="[400, 600]">
    <template #item="{ index }">
      <Slide :index="index" />
    </template>
  </Reel>

  <button @click="reelRef?.prev()">Prev</button>
  <button @click="reelRef?.next()">Next</button>
  <button @click="reelRef?.goTo(5)">Go to 5</button>
</template>

下一步