通用组件.md 19 KB

通用组件

本文引用的文件

  • MiniPlayer.vue
  • LazyImage.vue
  • Skeleton.vue
  • SkeletonList.vue
  • AudioDownload.vue
  • GenerationStatusBadge.vue
  • NetworkStatus.vue
  • audio.ts
  • index.vue(播放器页面)
  • index.vue(专辑列表页面)
  • detail.vue(AI生成详情页面)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 组件详解
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向AI有声书生成平台的通用组件,聚焦以下组件的实现与使用:MiniPlayer迷你播放器、LazyImage懒加载图片、Skeleton骨架屏系列、AudioDownload音频下载、GenerationStatusBadge生成状态徽章、NetworkStatus网络状态提示。文档从架构、数据流、状态管理、性能优化、错误处理与最佳实践等维度进行系统化梳理,并提供可视化图示帮助理解。

项目结构

通用组件集中于前端工程的组件目录,配合Pinia状态管理与页面使用示例,形成“组件-状态-页面”的清晰分层。

graph TB
subgraph "组件层"
MP["MiniPlayer.vue"]
LI["LazyImage.vue"]
SK["Skeleton.vue"]
SKL["SkeletonList.vue"]
AD["AudioDownload.vue"]
GSB["GenerationStatusBadge.vue"]
NS["NetworkStatus.vue"]
end
subgraph "状态层"
AST["audio.ts(Pinia Store)"]
end
subgraph "页面层"
PLY["pages/player/index.vue"]
ALB["pages/albums/index.vue"]
DET["pages/book-generator/detail.vue"]
end
MP --> AST
PLY --> MP
PLY --> AD
ALB --> SKL
DET --> GSB
NS --> PLY

图表来源

  • MiniPlayer.vue:1-166
  • LazyImage.vue:1-73
  • Skeleton.vue:1-72
  • SkeletonList.vue:1-283
  • AudioDownload.vue:1-179
  • GenerationStatusBadge.vue:1-180
  • NetworkStatus.vue:1-94
  • audio.ts:1-297
  • index.vue(播放器页面):1-200
  • index.vue(专辑列表页面):1-200
  • detail.vue(AI生成详情页面):1-200

章节来源

  • MiniPlayer.vue:1-166
  • audio.ts:1-297
  • index.vue(播放器页面):1-200

核心组件

  • MiniPlayer迷你播放器:在非播放器页面展示,绑定全局音频状态,支持封面渐变、播放/暂停、切歌跳转。
  • LazyImage懒加载图片:延迟真实资源加载,占位图过渡,事件透传,提升首屏性能。
  • Skeleton骨架屏:纯CSS动画骨架屏,支持文本/圆形/矩形/图片等类型,可自定义尺寸与动画。
  • AudioDownload音频下载:带重试、进度反馈、保存本地、Toast提示,适配H5与App双端。
  • GenerationStatusBadge生成状态徽章:统一状态映射与视觉风格,支持自定义覆盖,含呼吸/旋转动画。
  • NetworkStatus网络状态:H5监听online/offline,App监听uni-network,Toast提示断网/恢复。

章节来源

  • MiniPlayer.vue:1-166
  • LazyImage.vue:1-73
  • Skeleton.vue:1-72
  • AudioDownload.vue:1-179
  • GenerationStatusBadge.vue:1-180
  • NetworkStatus.vue:1-94

架构总览

组件通过Pinia Store共享音频状态,页面按需渲染组件;下载与网络状态分别独立监听与提示,形成解耦的UI增强层。

graph TB
UI["页面视图<br/>player/index.vue / albums/index.vue / book-generator/detail.vue"]
MP["MiniPlayer"]
AD["AudioDownload"]
SK["Skeleton / SkeletonList"]
GSB["GenerationStatusBadge"]
NS["NetworkStatus"]
ST["Pinia Store(audio.ts)"]
UI --> MP
UI --> AD
UI --> SK
UI --> GSB
UI --> NS
MP --> ST
AD --> ST

图表来源

  • index.vue(播放器页面):1-200
  • index.vue(专辑列表页面):1-200
  • detail.vue(AI生成详情页面):1-200
  • audio.ts:1-297

组件详解

MiniPlayer迷你播放器

  • 功能要点
    • 条件渲染:仅在非播放器页面且存在当前音频时显示。
    • 封面渐变:基于音色ID映射不同线性渐变背景。
    • 信息展示:标题与当前/总时长格式化显示。
    • 控制按钮:播放/暂停、下一首;点击整体跳转播放器页。
  • 状态管理
    • 依赖Pinia Store中的currentAudio、isPlaying、currentTime、duration等。
    • 播放/切歌通过Store方法触发,组件仅负责UI与路由跳转。
  • 性能与体验

    • 使用计算属性避免重复渲染;时间格式化函数轻量。
    • 固定定位与阴影提升可读性与层级感。

      sequenceDiagram
      participant Page as "页面"
      participant MP as "MiniPlayer"
      participant Store as "audio.ts"
      Page->>MP : 渲染组件
      MP->>Store : 读取 currentAudio/isPlaying
      MP->>MP : 计算封面渐变/格式化时间
      MP->>Store : togglePlay()/playNext()
      Store-->>Page : 更新播放状态
      MP->>Page : 导航到播放器页
      

图表来源

  • MiniPlayer.vue:1-166
  • audio.ts:1-297

章节来源

  • MiniPlayer.vue:1-166
  • audio.ts:1-297
  • index.vue(播放器页面):1-200

LazyImage懒加载图片

  • 功能要点
    • 属性:src、mode、placeholder、lazyLoad。
    • 行为:lazyLoad=true时先显示占位图,真实src变化后才加载;加载完成后添加loaded类,触发动画过渡。
    • 事件:load/error/click透传,便于统计与二次处理。
  • 性能优化
    • 通过占位图与opacity过渡减少白屏与跳闪。
    • 延迟真实资源加载,降低首屏阻塞。
  • 最佳实践

    • 为每个图片提供合适的占位图,尺寸与目标一致。
    • 对大图列表优先启用lazyLoad,避免一次性请求过多资源。

      flowchart TD
      Start(["组件挂载"]) --> Check["是否启用懒加载?"]
      Check --> |是| ShowPlaceholder["显示占位图"]
      Check --> |否| ShowReal["直接显示真实图"]
      ShowPlaceholder --> WatchSrc["监听src变化"]
      ShowReal --> WatchSrc
      WatchSrc --> SetReal["设置真实src"]
      SetReal --> OnLoad["onLoad回调"]
      OnLoad --> AddLoaded["添加loaded类"]
      AddLoaded --> EmitLoad["emit load事件"]
      SetReal --> OnError["onError回调"]
      OnError --> EmitError["emit error事件"]
      

图表来源

  • LazyImage.vue:1-73

章节来源

  • LazyImage.vue:1-73

Skeleton骨架屏系列

  • Skeleton基础骨架屏
    • 类型:text/circle/rect/image/custom。
    • 动画:默认带呼吸动画,可关闭。
    • 样式:通过CSS线性渐变+keyframes实现闪烁效果。
  • SkeletonList列表骨架屏
    • 布局:grid/list/search-result/history四种。
    • 结构:网格卡片、列表项、搜索结果项、历史卡片等。
    • 动画:统一shimmer动画,提升加载感知。
  • 使用场景

    • 列表/详情页数据拉取期间快速填充UI,改善感知性能。
    • 与实际数据结构保持一致的骨架尺寸与间距。

      classDiagram
      class Skeleton {
      +type : "text"|"circle"|"rect"|"image"|"custom"
      +width : string
      +height : string
      +animated : boolean
      }
      class SkeletonList {
      +layout : "grid"|"list"|"search-result"|"history"
      +count : number
      }
      SkeletonList --> Skeleton : "组合多个骨架元素"
      

图表来源

  • Skeleton.vue:1-72
  • SkeletonList.vue:1-283

章节来源

  • Skeleton.vue:1-72
  • SkeletonList.vue:1-283
  • index.vue(专辑列表页面):1-200

AudioDownload音频下载

  • 功能特性
    • 属性:url、filename、audioId。
    • 流程:显示loading → uni.downloadFile → 成功则uni.saveFile → Toast提示。
    • 进度:downloadTask.onProgressUpdate实时更新进度。
    • 重试:最多重试N次,指数退避等待。
  • 用户体验
    • 下载中显示百分比与进度条,失败弹窗提示,成功Toast确认。
  • 平台差异

    • H5端使用uni.showToast与原生online/offline事件。
    • App端使用uni.onNetworkStatusChange监听网络变化。

      sequenceDiagram
      participant UI as "页面"
      participant DL as "AudioDownload"
      participant UNI as "uni.downloadFile"
      participant SAVE as "uni.saveFile"
      UI->>DL : 点击下载
      DL->>DL : downloading=true, progress=0
      DL->>UNI : 发起下载任务
      UNI-->>DL : onProgressUpdate(progress)
      DL->>DL : 更新进度
      UNI-->>DL : success(res)
      alt 状态码200
      DL->>SAVE : 保存到本地
      SAVE-->>DL : success(saveRes)
      DL->>UI : Toast成功
      else 失败
      DL->>UI : 重试/弹窗提示
      end
      

图表来源

  • AudioDownload.vue:1-179
  • index.vue(播放器页面):84-92

章节来源

  • AudioDownload.vue:1-179
  • index.vue(播放器页面):1-200

GenerationStatusBadge生成状态徽章

  • 设计理念
    • 统一状态映射:包含“未开始/排队中/生成中/重试中/已完成/失败/已取消/草稿/规划中/待处理/运行中/成功/已支付/已退款/上传中/已公开/已暂停/已中断”等。
    • 线性阶段:大纲/内容/音频/视频各阶段状态,支持Book与Chapter级别。
    • 视觉风格:不同状态对应背景色与文字色,关键状态带呼吸/旋转动画。
    • 可扩展:支持customMap覆盖默认映射,满足业务定制。
  • 交互逻辑

    • 通过computed合并默认映射与自定义映射,动态决定图标与标签文本。
    • 状态类名驱动样式,保证一致性与可维护性。

      flowchart TD
      S["输入状态字符串"] --> Merge["合并默认映射与自定义映射"]
      Merge --> Lookup{"是否存在映射?"}
      Lookup --> |是| Pick["取出icon/label"]
      Lookup --> |否| Fallback["使用'?'与原始状态名"]
      Pick --> Render["渲染徽章"]
      Fallback --> Render
      

图表来源

  • GenerationStatusBadge.vue:1-180
  • detail.vue(AI生成详情页面)

章节来源

  • GenerationStatusBadge.vue:1-180
  • detail.vue(AI生成详情页面):1-200

NetworkStatus网络状态

  • 检测机制
    • H5端:监听window.online/offline事件,Toast提示断网/恢复。
    • App端:监听uni.onNetworkStatusChange,根据isConnected更新状态。
  • 提示策略

    • 断网时固定横幅提示,恢复时Toast提示,避免频繁打扰。
    • 仅在页面顶层展示,不影响主内容交互。

      sequenceDiagram
      participant Page as "页面"
      participant NS as "NetworkStatus"
      participant H5 as "H5在线事件"
      participant APP as "App网络事件"
      Page->>NS : 挂载组件
      alt H5环境
      NS->>H5 : 监听online/offline
      H5-->>NS : onOffline/onOnline
      else App环境
      NS->>APP : uni.onNetworkStatusChange
      APP-->>NS : isConnected
      end
      NS->>Page : Toast提示断网/恢复
      

图表来源

  • NetworkStatus.vue:1-94

章节来源

  • NetworkStatus.vue:1-94

依赖关系分析

  • 组件与Store
    • MiniPlayer与AudioDownload均依赖audio.ts中的播放状态与方法。
    • Store内部封装InnerAudioContext,统一播放控制与事件处理。
  • 组件与页面
    • 播放器页面引入MiniPlayer与AudioDownload,形成播放控制闭环。
    • 专辑列表页面使用SkeletonList提升加载体验。
    • AI生成详情页使用GenerationStatusBadge展示生成阶段。
  • 平台差异

    • NetworkStatus在H5与App采用不同API,但对外行为一致。

      graph LR
      MP["MiniPlayer"] --> ST["audio.ts"]
      AD["AudioDownload"] --> ST
      PLY["player/index.vue"] --> MP
      PLY --> AD
      ALB["albums/index.vue"] --> SKL["SkeletonList"]
      DET["book-generator/detail.vue"] --> GSB["GenerationStatusBadge"]
      NS["NetworkStatus"] --> PLY
      

图表来源

  • audio.ts:1-297
  • index.vue(播放器页面):1-200
  • index.vue(专辑列表页面):1-200
  • detail.vue(AI生成详情页面):1-200
  • NetworkStatus.vue:1-94

章节来源

  • audio.ts:1-297
  • index.vue(播放器页面):1-200
  • index.vue(专辑列表页面):1-200
  • detail.vue(AI生成详情页面):1-200
  • NetworkStatus.vue:1-94

性能考量

  • 渲染与状态
    • 使用computed避免重复计算;MiniPlayer条件渲染减少非必要DOM。
    • Store集中管理音频上下文与事件,避免多处重复监听。
  • 网络与IO
    • AudioDownload带重试与进度反馈,降低失败率与用户等待。
    • LazyImage延迟加载与占位图过渡,显著改善首屏体验。
  • 视觉与交互
    • Skeleton骨架屏与GenerationStatusBadge动画均为纯CSS,开销低。
    • NetworkStatus仅在断网时提示,避免常态干扰。
  • 最佳实践
    • 列表场景优先使用SkeletonList,确保骨架与真实结构一致。
    • 图片资源尽量提供占位图,开启lazyLoad,避免大图阻塞。
    • 下载流程中及时隐藏loading,失败后给出明确提示与重试入口。

故障排查指南

  • MiniPlayer不显示
    • 检查当前页面路由是否包含播放器关键字;确认Store中currentAudio是否存在。
    • 参考:MiniPlayer.vue:33-46
  • 播放异常
    • 查看Store中onError回调日志,核对audioContext.src与readyState。
    • 参考:audio.ts:64-74
  • 图片不显示或闪烁
    • 确认lazyLoad与realSrc赋值逻辑;检查onError事件是否触发。
    • 参考:LazyImage.vue:38-60
  • 下载失败
    • 检查downloadFile返回状态码;确认saveFile权限与存储空间。
    • 参考:AudioDownload.vue:71-129
  • 状态徽章显示异常
    • 检查状态字符串是否在映射表中;必要时使用customMap覆盖。
    • 参考:GenerationStatusBadge.vue:61-69
  • 网络提示不生效
    • H5端检查navigator.onLine;App端检查uni.onNetworkStatusChange是否注册。
    • 参考:NetworkStatus.vue:13-65

章节来源

  • MiniPlayer.vue:33-46
  • audio.ts:64-74
  • LazyImage.vue:38-60
  • AudioDownload.vue:71-129
  • GenerationStatusBadge.vue:61-69
  • NetworkStatus.vue:13-65

结论

上述通用组件围绕“状态共享、性能优化、体验一致”三大目标构建:通过Pinia集中管理音频状态,以组件形式在页面中复用;以骨架屏与懒加载优化首屏与滚动体验;以统一的状态徽章与网络提示提升信息传达效率。遵循本文的最佳实践与排障建议,可在复杂业务场景下保持组件的稳定性与可维护性。

附录

  • 组件属性与事件清单(摘要)
    • MiniPlayer
    • 属性:无(依赖Store)
    • 事件:无(内部路由跳转)
    • LazyImage
    • 属性:src、mode、placeholder、lazyLoad
    • 事件:load、error、click
    • Skeleton / SkeletonList
    • 属性:Skeleton(type,width,height,animated),SkeletonList(layout,count)
    • AudioDownload
    • 属性:url、filename、audioId
    • 事件:无(内部处理)
    • GenerationStatusBadge
    • 属性:status、customMap
    • 事件:无(纯展示)
    • NetworkStatus
    • 属性:无(自动检测)
    • 事件:无(内部Toast)