# jit-viewer 中文文档

JitViewer 是一个面向 Vue 3、React 和原生 JavaScript 的文档预览 SDK。

当前支持 PDF、DOCX、XLSX/XLS、CSV/TSV、PPTX/PPT、OFD、TXT、Markdown、代码高亮预览、HTML、图片、视频、CAD 图纸，以及 3D 模型预览，并内置水印能力与请求适配器机制。

[English README](./README.md)

## 本次更新

### 1.5.0 - 2026-04-12

- 重写 PDF 渲染引擎：使用 `pdfjs-dist` 替换 `@vue-office/pdf`，解决超过 5 页无法渲染的问题
- PDF Worker 完全离线化：`?raw` 内嵌 Worker 脚本，无需外部 CDN，支持内网部署
- 新增版权保护升级：检测版权元素被删除时触发全屏锁屏，防止版权移除
- 修复版权保护误触发：修复初始化阶段误判元素隐藏导致的锁屏 bug
- 新增大文件加载提示：文件超过 5MB 时分阶段显示正在读取/解析中...进度提示
- 删除无用依赖：移除 `@vue-office/pdf`、`vue-demi`、`@rollup/plugin-commonjs` 等废弃依赖
- 修复 TXT 文件乱码问题：自动检测编码（GBK/UTF-8），确保中文内容正确显示

### 1.3.0 - 2026-04-07

- 新增 `model3d` 文件类型，首批支持 `GLB / glTF / STL` 3D 模型预览
- 新增 3D 运行时 API：重置视角、自动旋转、线框切换、动画切换、截图、灯光/材质调参与预设获取/应用
- 新增 3D 内置预设库，支持 `产品展台 / 白模审阅 / 夜景轮廓 / 暖光陈列` 一键切换
- 完整 HTML demo 新增 3D STL / glTF 示例、调试面板、预设导入导出与内置预设选择器

### 1.2.2 - 2026-04-06

- 增强视频预览能力，支持续播、播放回调、运行时控制 API 与控件裁剪配置
- 新增 `video.nativeControls`，可独立控制浏览器原生视频工具条显示
- 修复视频加载后自定义控件不立即显示的问题
- 修复视频工具栏 `More` 面板被顶部工具栏遮挡的问题
- 完整 HTML demo 新增视频调试面板，并优化本地 SDK 资源加载顺序

完整变更见 [CHANGELOG.md](./CHANGELOG.md)。

## 特性

- 多格式预览：PDF、Office、OFD、Markdown、代码、HTML、图片、视频、CSV
- 3D 模型预览：内建 `GLB / glTF / STL` 直预览能力
- CAD 预览：内建 `DXF` 前端直渲染，支持 `DWG / DWF` 通过转换产物接入
- 跨框架使用：Vue 3、React、原生 HTML/JS
- 内置工具栏：缩放、旋转、打印、下载、分页
- 主题与国际化：浅色 / 深色，`zh-CN` / `en`
- 水印能力：文本水印、图片水印、透明度、旋转、平铺间距、顶层/底层显示
- 文件源支持：本地文件、远程 URL、Blob、ArrayBuffer、代理地址、自定义请求适配器

## 安装

```bash
npm install jit-viewer
```

## 快速开始

### Vue 3

```vue
<template>
  <div ref="containerRef" class="viewer-container"></div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import { createViewer } from 'jit-viewer'
import 'jit-viewer/style.css'

const containerRef = ref<HTMLElement | null>(null)
let viewer: ReturnType<typeof createViewer> | null = null

onMounted(() => {
  viewer = createViewer({
    target: containerRef.value!,
    file: '/demo/test.csv',
    toolbar: true,
    width: '100%',
    height: 640
  })

  viewer.mount()
})

onUnmounted(() => {
  viewer?.destroy()
})
</script>

<style scoped>
.viewer-container {
  width: 100%;
  height: 640px;
}
</style>
```

### React

```tsx
import { useEffect, useRef } from 'react'
import { createViewer, type ViewerInstance } from 'jit-viewer'
import 'jit-viewer/style.css'

export default function App() {
  const containerRef = useRef<HTMLDivElement | null>(null)
  const viewerRef = useRef<ViewerInstance | null>(null)

  useEffect(() => {
    if (!containerRef.current)
      return

    viewerRef.current = createViewer({
      target: containerRef.current,
      file: '/demo/test.mp4',
      toolbar: true,
      height: 640
    })

    viewerRef.current.mount()

    return () => viewerRef.current?.destroy()
  }, [])

  return <div ref={containerRef} style={{ width: '100%', height: 640 }} />
}
```

### 原生 HTML / JS

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>JitViewer Demo</title>
  <link rel="stylesheet" href="https://unpkg.com/jit-viewer@1.3.0/dist/iife/jit-viewer.min.css" />
</head>
<body>
  <div id="viewer" style="width:100%;height:640px;"></div>

  <script src="https://unpkg.com/jit-viewer@1.3.0/dist/iife/jit-viewer.min.js"></script>
  <script>
    const viewer = JitViewer.createViewer({
      target: '#viewer',
      file: '/demo/test.pdf',
      toolbar: true,
      width: '100%',
      height: 640
    })

    viewer.mount()
  </script>
</body>
</html>
```

## 核心 API

### `createViewer(options)`

创建预览器实例。

`ViewerOptions` 里最常用的配置如下：

| 选项 | 类型 | 说明 |
| --- | --- | --- |
| `target` | `HTMLElement \| string` | 挂载目标 |
| `file` | `FileSource` | 文件源 |
| `type` | `FileType` | 当自动识别不够稳定时显式指定文件类型 |
| `filename` | `string` | 展示和下载时使用的文件名 |
| `toolbar` | `ToolbarConfig \| boolean` | 工具栏配置 |
| `theme` | `Theme` | `light`、`dark` 或自定义主题 |
| `locale` | `Locale` | `zh-CN`、`en` 或自定义语言 |
| `watermark` | `WatermarkConfig \| null` | 预览层水印配置 |
| `proxyUrl` | `string` | 自定义代理地址 |
| `requestAdapter` | `RequestAdapter` | 自定义请求适配器 |
| `video` | `VideoOptions` | 视频预览配置，支持禁用拖动续播与播放回调 |
| `cad` | `CadOptions` | CAD 预览配置，支持 `DXF` 直渲染和 `DWG / DWF` 适配器接入 |
| `model3d` | `Model3DOptions` | 3D 模型预览配置，支持 `GLB / glTF / STL` 与转换结果接入 |
| `renderOptions` | `{ zoom?: number; rotate?: number; page?: number }` | 初始渲染状态 |

### `ViewerInstance`

| 方法 | 说明 |
| --- | --- |
| `mount(target?)` | 挂载预览器 |
| `destroy()` | 销毁预览器 |
| `setFile(file, filename?)` | 替换当前文件 |
| `setOptions(options)` | 运行时更新文件、主题、工具栏、水印等配置 |
| `getFile()` | 获取当前文件信息 |
| `zoom(scale)` | 设置缩放 |
| `rotate(degree)` | 设置旋转 |
| `reset()` | 重置缩放和旋转 |
| `fullscreen(enable?)` | 切换全屏 |
| `prevPage()` / `nextPage()` / `gotoPage(page)` | 分页控制 |
| `getPageInfo()` | 获取页码状态 |
| `print()` | 打印当前内容 |
| `download()` | 下载当前文件 |
| `playVideo()` / `pauseVideo()` / `toggleVideoPlayback()` | 控制视频播放 |
| `seekVideo(time)` | 跳转到指定视频时间 |
| `getVideoState()` | 获取当前视频播放状态 |
| `resetModel3DCamera()` | 重置 3D 模型视角 |
| `setModel3DAutoRotate(enabled)` | 控制 3D 自动旋转 |
| `setModel3DAutoRotateSpeed(speed)` | 设置自动旋转速度 |
| `setModel3DExposure(exposure)` | 设置 3D 曝光 |
| `setModel3DLightIntensity(intensity)` | 设置场景光照强度 |
| `setModel3DMaterialRoughness(value)` | 调整材质粗糙度 |
| `setModel3DMaterialMetalness(value)` | 调整材质金属度 |
| `toggleModel3DWireframe()` | 切换 3D 线框模式 |
| `toggleModel3DAnimation()` | 切换 3D 动画播放/暂停 |
| `captureModel3DScreenshot()` | 导出 3D 预览截图 |
| `getModel3DState()` | 获取当前 3D 模型状态 |
| `applyModel3DPreset(preset)` | 应用一组 3D 预设 |
| `getModel3DPreset()` | 导出当前 3D 预设 |
| `applyBuiltInModel3DPreset(id)` | 应用内置 3D 场景预设 |
| `getBuiltInModel3DPresets()` | 获取内置 3D 预设列表 |
| `setTheme(theme)` | 切换主题 |
| `setLocale(locale)` | 切换语言 |
| `setToolbar(config)` | 更新工具栏 |
| `on(event, handler)` / `off(event, handler)` | 事件订阅 |
| `getState()` | 获取运行时状态 |

## 水印

通过 `ViewerOptions.watermark` 配置水印。水印只作用于预览层，不会修改原始文件。

```ts
import { createViewer } from 'jit-viewer'
import 'jit-viewer/style.css'

const viewer = createViewer({
  target: '#viewer',
  file: '/demo/report.pdf',
  watermark: {
    type: 'text',
    content: '内部资料',
    opacity: 0.18,
    rotate: -24,
    gapX: 140,
    gapY: 90,
    position: 'top'
  }
})

viewer.mount()
```

## 支持格式

| 类型 | 扩展名 |
| --- | --- |
| PDF | `.pdf` |
| Word | `.docx` |
| Excel | `.xlsx`, `.xls` |
| CSV | `.csv`, `.tsv` |
| PowerPoint | `.pptx`, `.ppt` |
| OFD | `.ofd` |
| 文本 | `.txt` |
| Markdown | `.md`, `.markdown` |
| HTML | `.html`, `.htm` |
| 图片 | `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`, `.svg`, `.bmp`, `.tiff`, `.tif`, `.ico` |
| 视频 | `.mp4`, `.webm`, `.ogg`, `.ogv`, `.mov` |
| CAD | `.dxf`（内建直渲染）, `.dwg`, `.dwf`, `.dwfx`, `.dwt`（通过 `cad.previewUrl` / `cad.adapter` 接入） |
| 3D 模型 | `.glb`, `.gltf`, `.stl`（首批直预览）, `.obj`, `.ply`（适配器/扩展接入） |

## 视频预览

视频预览支持禁止用户拖动进度条、按上次播放进度继续播放，以及播放/暂停/播放结束回调。

开启 `disableSeek` 后，SDK 会自动切换到自定义控制栏，避免浏览器原生进度条仍然可拖动。
通过 `nativeControls: false` 可以单独隐藏浏览器原生视频工具条。
当 `nativeControls: false` 且未显式关闭自定义控件时，SDK 会自动回退到自定义控件或工具栏控件。
如果主工具栏启用了 `video` 项，视频控制会优先显示在主工具栏中，画面内控件会自动隐藏。
默认会把 `播放 / 重播 / 时间 / 进度` 放在主工具栏，把 `音量 / 倍速` 收纳到 `More` 菜单。

```ts
import { createViewer } from 'jit-viewer'
import 'jit-viewer/style.css'

const viewer = createViewer({
  target: '#viewer',
  file: '/demo/training.mp4',
  video: {
    disableSeek: true,
    nativeControls: false,
    resumePlayback: 'local',
    toolbarItems: ['playback', 'time', 'progress'],
    toolbarMoreItems: ['mute', 'speed'],
    customControlItems: ['playback', 'progress', 'time'],
    onEnded: (state) => {
      console.log('播放结束', state.currentTime)
    }
  }
})

viewer.mount()

await viewer.playVideo()
viewer.pauseVideo()
viewer.seekVideo(120)
```

如果你希望通过事件总线监听视频状态，也可以使用：

```ts
viewer.on('video:ended', (state) => {
  console.log('ended', state.currentTime)
})
```

如果你需要裁剪主工具栏里的视频控件，也可以直接这样配：

```ts
const viewer = createViewer({
  target: '#viewer',
  file: '/demo/training.mp4',
  toolbar: {
    position: 'both',
    items: [
      { type: 'fullscreen' },
      { type: 'video', options: { items: ['playback', 'time'], moreItems: ['mute', 'speed'] } },
      { type: 'download' }
    ]
  }
})
```

## CAD 预览

`DXF` 默认会在浏览器端直渲染；`DWG / DWF` 等格式建议先由服务端转换成 `PDF / SVG / HTML`，再交给 SDK 展示。

```ts
import { createViewer } from 'jit-viewer'
import 'jit-viewer/style.css'

const viewer = createViewer({
  target: '#viewer',
  file: '/demo/site-plan.dwg',
  cad: {
    previewUrl: '/api/cad/preview/site-plan.svg'
  }
})

viewer.mount()
```

## 3D 模型预览

3D 预览当前首批支持 `GLB / glTF / STL`。建议浏览器端优先使用 `GLB / STL`；对于工程格式或业务自己的转换链路，可以通过 `model3d.previewUrl` 或 `model3d.adapter` 接入统一预览结果。

```ts
import { createViewer } from 'jit-viewer'
import 'jit-viewer/style.css'

const viewer = createViewer({
  target: '#viewer',
  file: '/demo/part.stl',
  model3d: {
    autoRotate: true,
    autoRotateSpeed: 1.2,
    showGrid: true,
    showAxes: true,
    environment: 'studio',
    exposure: 1,
    lightIntensity: 1
  }
})

viewer.mount()
```

运行时可以继续细调 3D 场景：

```ts
viewer.setModel3DAutoRotate(true)
viewer.setModel3DAutoRotateSpeed(1.4)
viewer.setModel3DExposure(1.1)
viewer.setModel3DLightIntensity(1.2)
viewer.setModel3DMaterialRoughness(0.32)
viewer.setModel3DMaterialMetalness(0.46)
```

也可以直接导出和应用预设：

```ts
const preset = viewer.getModel3DPreset()

viewer.applyModel3DPreset({
  environment: 'neutral',
  exposure: 1.05,
  lightIntensity: 0.95
})

viewer.applyBuiltInModel3DPreset('white-model-review')
console.log(preset, viewer.getBuiltInModel3DPresets())
```

## 相关链接

- [English README](./README.md)
- [更新日志](./CHANGELOG.md)
- [GitHub](https://github.com/jitOffice/jit-viewer-sdk)
- [主页](https://jitword.com/jit-viewer.html)
