# 使用说明

一套 `core`（路径数学、样式、`createOrbit` 动画驱动）+ React / Vue 两套薄封装。  
**不是**三个独立产品，而是：**一个库、两种框架、安装或复制二选一**。

| | React | Vue |
|--|--------|-----|
| **npm** | [`@fxshelf/card-orbit`](https://www.npmjs.com/package/@fxshelf/card-orbit) | `@fxshelf/card-orbit/vue` |
| **CDN `<script>`** | [unpkg](https://unpkg.com/@fxshelf/card-orbit/dist/card-orbit.iife.js) → 全局 `CardOrbit` | 暂无（SFC 源码发布） |
| **复制源码** | 拷 `src/core` + `src/react` | 拷 `src/core` + `src/vue` |

动效原理见 [专业版](./动效说明-专业.md) / [大白话版](./动效说明-大白话.md) / [轨道坐标演示](./轨道演示.html)。

---

## npm 安装

```bash
npm install @fxshelf/card-orbit
```

按需安装对应框架（peer）：

- React：`react` / `react-dom`（>= 18）
- Vue：`vue`（>= 3.3）

样式统一：

```ts
import '@fxshelf/card-orbit/styles.css'
```

### React

```tsx
import { CardOrbit, CardOrbitMobile } from '@fxshelf/card-orbit'
import '@fxshelf/card-orbit/styles.css'

const images = ['/a.webp', '/b.webp', '/c.webp']

export function Hero() {
  return (
    <>
      <CardOrbitMobile images={images} />
      <CardOrbit images={images} />
    </>
  )
}
```

### Vue

Vue 入口以 **源码 SFC（`.vue`）** 发布，不会预编译进 `dist`。  
目标项目需要能编译 `.vue`（例如 **Vite + `@vitejs/plugin-vue`**）。仓库自带 demo 仅为 React。

```vue
<script setup lang="ts">
import { CardOrbit, CardOrbitMobile } from '@fxshelf/card-orbit/vue'
import '@fxshelf/card-orbit/styles.css'

const images = ['/a.webp', '/b.webp', '/c.webp']
</script>

<template>
  <CardOrbitMobile :images="images" />
  <CardOrbit :images="images" />
</template>
```

---

## CDN / `<script>` 直引（React）

适合静态页、快速试用或完全不想引入构建步骤的场景。  
React 版提供自包含浏览器产物 **`dist/card-orbit.iife.js`**（约 10 KB，零依赖），挂载全局变量 **`CardOrbit`**。

要求：页面先加载 **React 18.x UMD**（React 19 起官方不再提供 UMD 构建），渲染用 `react-dom`。

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <link rel="stylesheet" href="https://unpkg.com/@fxshelf/card-orbit/dist/index.css" />
</head>
<body>
  <div id="hero"></div>

  <!-- 1. React 18 UMD（提供全局 React / ReactDOM） -->
  <script crossorigin src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>

  <!-- 2. card-orbit 浏览器产物（提供全局 CardOrbit） -->
  <script src="https://unpkg.com/@fxshelf/card-orbit/dist/card-orbit.iife.js"></script>

  <script>
    var images = ['/a.webp', '/b.webp', '/c.webp']
    ReactDOM.createRoot(document.getElementById('hero')).render(
      React.createElement(React.Fragment, null,
        React.createElement(CardOrbit.CardOrbitMobile, { images: images }),
        React.createElement(CardOrbit.CardOrbit, { images: images }),
      ),
    )
  </script>
</body>
</html>
```

说明：

- 全局 `CardOrbit` 上有 `CardOrbit`、`CardOrbitMobile` 及 core 工具（`createOrbit` / `samplePath` 等），与 npm 主入口一致；props 与下文完全相同。
- 样式引 `dist/index.css` 或 `dist/card-orbit.iife.css`（内容相同）。
- CDN 也可用 jsDelivr：`https://cdn.jsdelivr.net/npm/@fxshelf/card-orbit/dist/card-orbit.iife.js`，或短地址 `https://cdn.jsdelivr.net/npm/@fxshelf/card-orbit`（`package.json` 的 `jsdelivr` / `unpkg` 字段已指向该产物）。
- 可锁定版本：`@fxshelf/card-orbit@0.1.6/...`（推荐生产环境）。
- 顺序要求：React 必须在 card-orbit 之前加载；顺序不对时产物会抛出明确报错。
- **不要**用 jsDelivr 的 `gh/.../dist` 直链：`dist/` 不进 Git，会 404。
- 完整可打开示例：[CDN示例.html](./CDN示例.html)（默认走 unpkg；本地已 build 时可改成相对路径 `../dist/...`）。

**Vue 暂无 script 直引产物**：Vue 入口以 `.vue` SFC 源码发布，需要使用方环境能编译 SFC。Vue 场景请用 [npm 安装](#npm-安装) 或 [复制源码](#复制进项目不经过-npm)。

> 旧无 scope 包名 `card-orbit` 已迁移至 `@fxshelf/card-orbit`，请改用新包名。

---

## 复制进项目（不经过 npm）

从本仓库拷贝：

```
src/core/     # 必拷
src/react/    # 仅 React 项目
src/vue/      # 仅 Vue 项目
```

建议放到例如 `components/card-orbit/`：

```
components/card-orbit/
  core/
  react/   或  vue/
```

1. 组件内相对路径已是 `../core/...`，保持 `core` 与 `react`/`vue` 同级即可。
2. 引入一次样式：`import './core/styles.css'`。
3. 当本地组件使用。

### React

```tsx
import { CardOrbit, CardOrbitMobile } from './components/card-orbit/react'
import './components/card-orbit/core/styles.css'
```

### Vue

```ts
import { CardOrbit, CardOrbitMobile } from './components/card-orbit/vue'
import './components/card-orbit/core/styles.css'
```

---

## 组件与 props

| 组件 | 作用 |
|------|------|
| `CardOrbit` | 桌面 3D 轨迹（默认仅 `lg+` / 1024px 显示） |
| `CardOrbitMobile` | 窄屏横向跑马灯（默认 `lg+` 隐藏） |

React / Vue **props 名称一致**。图片 URL 由调用方提供，包内不捆绑资源。

### `CardOrbit`

| Prop | 默认 | 说明 |
|------|------|------|
| `images` | — | 图片 URL 数组（必填） |
| `alts` | — | 与图片一一对应的 alt |
| `className` / `style` | — | 根节点；Vue 也可用同名 props |
| `stageClassName` / `cardClassName` / `imageClassName` | — | 子节点 class |
| `autoSpeed` | `45e-6` | 未拖动时自动推进 |
| `dragSensitivity` | `8e-4` | 指针拖动灵敏度 |
| `activeWindow` | `0.72` | 可见相位窗口 `(0, 1)` |
| `perspective` | `3400` | CSS perspective（px） |
| `ariaLabel` | `'Card orbit carousel'` | 无障碍标签 |
| `desktopOnly` | `true` | 是否仅大屏显示 |

### `CardOrbitMobile`

| Prop | 默认 | 说明 |
|------|------|------|
| `images` / `alts` | — | 同桌面 |
| `className` / `style` | — | 根节点 |
| `trackClassName` / `cardClassName` / `imageClassName` | — | 子节点 class |
| `hideOnDesktop` | `true` | `lg+` 是否隐藏 |
| `durationSec` | `28` | 跑马灯一周时长（秒） |

典型搭配：窄屏用 `CardOrbitMobile`，宽屏用 `CardOrbit`，二者同时挂载、靠内置 CSS 互斥显示。

---

## 目录与构建说明

```
src/core/     # 无框架：path.ts、styles.css、createOrbit.ts
src/react/    # React 适配 → npm 主入口打包进 dist/
src/vue/      # Vue 适配 → 以源码形式随包发布（@fxshelf/card-orbit/vue）
src/browser/  # 浏览器直引构建的全局 shim（react / jsx-runtime，不随包发布）
dist/         # 产物：index.js/.cjs/.d.ts（React 入口）、card-orbit.iife.js（浏览器直引）、CSS
```

- 在 monorepo 根执行 `npm run build`，或在本包目录执行 `npm run build`，只打包 **React** 到 `dist/`；其中 `card-orbit.iife.js` 通过 `src/browser/` 的 shim 把 `react` / `react/jsx-runtime` 指到全局 `React`，因此产物自包含。
- Vue 走 `package.json` 的 `exports["./vue"]`，指向 `src/vue`。
- 复制使用时不必跑本仓库的 build。
- 文档站在仓库 `apps/site`（fxshelf 总览）。
