npm package: @reskin/video
Description: <a href="https://www.npmjs.com/package/@reskin/video" target="_blank">![NPM Version](https://img.shields.io/npm/v/@reskin/video?label=@reskin/video)</a>
Latest version: 0.1.0

# RkVideo 视频播放器组件

<a href="https://www.npmjs.com/package/@reskin/video" target="_blank">![NPM Version](https://img.shields.io/npm/v/@reskin/video?label=@reskin/video)</a>

基于 [video.js](https://videojs.com/) 封装的 Angular 视频播放器组件，提供丰富的配置选项和事件回调，支持多种视频格式和自定义控制。

## 功能特性

- 🎬 支持多种视频格式（MP4、WebM、Ogg 等）
- 🎨 响应式设计，自适应容器大小
- ⚙️ 丰富的配置选项（自动播放、循环、静音等）
- 🎯 完整的事件回调系统
- 🔒 支持禁用进度条拖动（防止快进）
- 🌐 内置中文语言包
- 📱 支持画中画模式
- ⚡ 可配置播放速率

## 安装

```bash
npm install video.js@8 --save
npm install @reskin/video --save
```

## 样式引入

video 组件支持两种样式加载方式，可根据项目需求选择：

### 方式一：动态加载（默认，推荐用于按需加载场景）

组件内部使用 `rkLoadStyles` 指令自动加载样式，无需额外配置。样式会在组件首次使用时动态加载。

**优点**：
- 无需全局配置
- 按需加载，减少初始包体积
- 适合只在部分页面使用视频的场景

**注意**：需要确保 `angular.json` 中已配置 video.js 静态资源复制（项目已配置）。

### 方式二：全局引入（推荐用于频繁使用场景）

如果项目中多处使用视频组件，建议在全局样式文件中引入，避免重复加载。

在 `src/styles.scss` 中添加：

```scss
@import 'video.js/dist/video-js.css';
```

或在 `angular.json` 中配置：

```json
{
  "styles": [
    "node_modules/video.js/dist/video-js.css",
    "src/styles.scss"
  ]
}
```

**优点**：
- 样式在应用启动时就加载完成
- 避免样式闪烁
- 浏览器缓存友好

**缺点**：
- 增加初始包体积（约 20KB）

## 基础用法

### 1. 导入模块

```typescript
import { NgModule } from '@angular/core';
import { RkVideoModule } from '@reskin/video';

@NgModule({
    imports: [RkVideoModule],
})
export class AppModule {}
```

### 2. 使用组件

```html
<rk-video
    src="https://example.com/video.mp4"
    type="video/mp4"
    [autoplay]="false"
    [controls]="true"
    poster="https://example.com/poster.jpg">
</rk-video>
```

## API 参数

### 输入属性 (Inputs)

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| `src` | 视频源地址 | `string` | - |
| `type` | 视频 MIME 类型 | `string` | - |
| `width` | 视频容器宽度 | `string \| number` | - |
| `height` | 视频容器高度 | `string \| number` | - |
| `autoplay` | 是否自动播放 | `boolean` | `false` |
| `controls` | 是否显示控制条 | `boolean` | `true` |
| `loop` | 是否循环播放 | `boolean` | `false` |
| `muted` | 是否静音 | `boolean` | `false` |
| `poster` | 海报图片地址 | `string` | - |
| `preload` | 预加载策略 | `'auto' \| 'metadata' \| 'none'` | `'auto'` |
| `aspectRatio` | 视频宽高比 | `string` | - |
| `fluid` | 是否自适应容器大小 | `boolean` | `true` |
| `disablePictureInPicture` | 是否禁用画中画 | `boolean` | `false` |
| `playbackRates` | 可选播放速率列表 | `number[]` | - |
| `progressAdjust` | 是否允许拖动进度条 | `boolean` | `true` |
| `progressAdjustThreshold` | 进度调整阈值（秒） | `number` | `2` |
| `currentTime` | 初始播放位置（秒） | `number` | `0` |
| `notSupportedMessage` | 不支持时的提示信息 | `string` | `'此视频暂无法播放，请稍后再试'` |
| `options` | 额外的 video.js 配置 | `RkVideoOptions` | - |

### 输出事件 (Outputs)

| 事件 | 说明 | 回调参数 |
|------|------|----------|
| `readyChange` | 播放器初始化完成 | `Player` |
| `loadeddataChange` | 视频元数据加载完成 | `Player` |
| `playingChange` | 视频开始播放 | `Player` |
| `pauseChange` | 视频暂停 | `RkVideoEventData` |
| `timeupdateChange` | 播放进度更新 | `RkVideoEventData` |
| `errorChange` | 播放错误 | `Player` |
| `endedChange` | 播放结束 | `RkVideoEventData` |

### 类型定义

```typescript
/**
 * 视频播放事件数据
 */
export interface RkVideoEventData {
    currentTime: number;  // 当前播放时间（秒）
    player: Player;       // 播放器实例
}

/**
 * video.js 配置选项
 */
export interface RkVideoOptions {
    sources?: Array<{ src?: string; type?: string }>;
    autoplay?: boolean;
    controls?: boolean;
    loop?: boolean;
    muted?: boolean;
    poster?: string;
    preload?: 'auto' | 'metadata' | 'none';
    aspectRatio?: string;
    disablePictureInPicture?: boolean;
    fluid?: boolean;
    language?: string;
    notSupportedMessage?: string;
    playbackRates?: number[];
    [key: string]: any;  // 其他 video.js 配置
}
```

## 使用示例

### 基础播放器

```html
<rk-video
    src="https://example.com/video.mp4"
    type="video/mp4"
    poster="https://example.com/poster.jpg">
</rk-video>
```

### 自定义尺寸和宽高比

```html
<rk-video
    src="https://example.com/video.mp4"
    width="800px"
    height="450px"
    aspectRatio="16:9">
</rk-video>
```

### 自动播放和循环

```html
<rk-video
    src="https://example.com/video.mp4"
    [autoplay]="true"
    [loop]="true"
    [muted]="true">
</rk-video>
```

### 禁用进度条拖动

适用于在线教育、培训视频等需要防止快进的场景：

```html
<rk-video
    src="https://example.com/course.mp4"
    [progressAdjust]="false"
    [progressAdjustThreshold]="1">
</rk-video>
```

### 多倍速播放

```html
<rk-video
    src="https://example.com/video.mp4"
    [playbackRates]="[0.5, 1, 1.5, 2]">
</rk-video>
```

### 监听播放事件

```typescript
import { Component } from '@angular/core';
import { RkVideoEventData } from '@reskin/video';
import Player from 'video.js/dist/types/player';

@Component({
    selector: 'app-video-demo',
    template: `
        <rk-video
            src="https://example.com/video.mp4"
            (readyChange)="onReady($event)"
            (playingChange)="onPlaying($event)"
            (pauseChange)="onPause($event)"
            (timeupdateChange)="onTimeUpdate($event)"
            (endedChange)="onEnded($event)">
        </rk-video>
    `,
})
export class VideoDemoComponent {
    onReady(player: Player): void {
        console.log('播放器已就绪', player);
    }

    onPlaying(player: Player): void {
        console.log('开始播放');
    }

    onPause(data: RkVideoEventData): void {
        console.log('暂停播放，当前时间：', data.currentTime);
    }

    onTimeUpdate(data: RkVideoEventData): void {
        console.log('播放进度：', data.currentTime);
    }

    onEnded(data: RkVideoEventData): void {
        console.log('播放结束');
    }
}
```

### 从指定位置开始播放

```html
<rk-video
    src="https://example.com/video.mp4"
    [currentTime]="60">
</rk-video>
```

### 使用高级配置

```typescript
import { Component } from '@angular/core';
import { RkVideoOptions } from '@reskin/video';

@Component({
    selector: 'app-video-demo',
    template: `
        <rk-video
            src="https://example.com/video.mp4"
            [options]="videoOptions">
        </rk-video>
    `,
})
export class VideoDemoComponent {
    videoOptions: RkVideoOptions = {
        playbackRates: [0.5, 1, 1.5, 2],
        aspectRatio: '16:9',
        fluid: true,
        responsive: true,
        // 更多 video.js 配置项
        // 参考：https://videojs.com/guides/options
    };
}
```

## 注意事项

### 样式引入

必须在全局样式中引入 `video.js` 的 CSS 文件，否则播放器样式将无法正常显示。

### 自动播放限制

现代浏览器对自动播放有严格限制，通常需要满足以下条件之一：
- 视频静音（`muted="true"`）
- 用户与页面有过交互
- 网站被添加到自动播放白名单

### 进度控制

当 `progressAdjust` 设置为 `false` 时：
- 用户无法通过拖动进度条快进或后退
- `progressAdjustThreshold` 参数控制检测阈值（默认 2 秒）
- 适用于需要强制顺序观看的场景

### 视频格式

推荐使用 MP4 格式（H.264 编码），兼容性最好。其他格式支持情况：
- WebM：Chrome、Firefox、Opera
- Ogg：Firefox、Chrome、Opera

### 性能优化

- 使用 `preload="metadata"` 或 `preload="none"` 减少初始加载
- 合理设置 `poster` 海报图提升用户体验
- 大视频文件建议使用 CDN 加速

## 浏览器兼容性

- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
- iOS Safari 11+
- Android Chrome 60+

## 相关链接

- [video.js 官方文档](https://videojs.com/)
- [video.js 配置选项](https://videojs.com/guides/options)
- [video.js API 文档](https://docs.videojs.com/)

## 许可证

MIT