showtime-components
v0.2.6
Published
Vue 3 components for polished mobile showtime interactions.
Readme
showtime-components
一个面向移动端交互体验的 Vue 3 组件包,当前提供:
ShowtimeBottomSheetShowtimeActionBarShowtimeRevealBottomSheetShowtimeMaintenancePageShowtimeSkeletonShowtimeSkeletonLineShowtimeSkeletonShapeShowtimeWaterfallShowtimeTwoLineEllipsisShowtimeUpload
安装
pnpm add showtime-components如果你在本地 workspace 中使用,也可以直接通过 workspace 依赖接入。
基础使用
<script setup lang="ts">
import { ref } from 'vue'
import {
ShowtimeActionBar,
ShowtimeBottomSheet,
ShowtimeMaintenancePage,
ShowtimeRevealBottomSheet,
ShowtimeSkeleton,
ShowtimeSkeletonLine,
ShowtimeSkeletonShape,
ShowtimeTwoLineEllipsis,
ShowtimeWaterfall,
type ShowtimeBottomSheetDragPayload,
type ShowtimeSheetSnap
} from 'showtime-components'
import 'showtime-components/style.css'
const snap = ref<ShowtimeSheetSnap>('peek')
const followed = ref(false)
function handleDrag(payload: ShowtimeBottomSheetDragPayload) {
console.log('sheet y:', payload.y)
}
</script>
<template>
<ShowtimeBottomSheet
v-model:snap="snap"
@drag="handleDrag"
>
<template #header>
<ShowtimeActionBar v-model:follow-active="followed" />
</template>
<div>这里是内容区域</div>
</ShowtimeBottomSheet>
</template>样式引入
如果你的构建流程需要显式引入样式,可以加上:
import 'showtime-components/style.css'共享样式定制
样式文件提供可覆盖的 --showtime-* token,用于统一定制圆角、色彩、阴影和动效:
:root {
--showtime-color-surface: #fffdf8;
--showtime-color-text: #263238;
--showtime-radius-md: 8px;
--showtime-radius-lg: 24px;
--showtime-shadow-sheet: 0 -12px 36px rgba(23, 42, 34, 0.16);
}完整 token 列表和局部覆盖示例见 样式定制。组件实例 props(例如 panelBackground 和 panelRadius)优先于全局 token。
Skeleton 与 Waterfall
ShowtimeSkeleton 默认开启单束清晰高亮扫光,光束完整离开占位面后再进入下一轮;可通过 :animation="false" 关闭。根组件支持 baseColor、highlightColor、animationDuration、animationAngle、animationDirection 和 borderRadius;其中 animationAngle 控制扫光带的倾斜角度,animationDirection 支持 ltr、rtl、ttb、btt 四种移动方向。提高 highlightColor 与 baseColor 的对比度可获得更醒目的效果。这些视觉配置会传给 skeleton 插槽内的后代。ShowtimeSkeletonLine 与 ShowtimeSkeletonShape 还可以单独覆盖颜色和圆角,分别支持 rows、widths、lineHeight、lineSpacing、shape 与 size。自定义骨架插槽可用 showtime-skeleton__surface 标记实际占位面,避免包装容器重复扫光。
ShowtimeWaterfall 通过 ResizeObserver 测量实际卡片高度并分配到最短列,在接近页面底部时发出 load 事件。由父组件维护 loading 和 finished;加载中骨架卡片会均分到各列并默认显示扫光动画。
详细 API 参见 Skeleton 与 Waterfall。
ShowtimeTwoLineEllipsis
ShowtimeTwoLineEllipsis 默认用实际渲染字体把正文限制在两行,也可以通过 lineCount 自定义折叠行数。最后一行会为“更多”入口保留真实宽度,点击后展示全部正文;容器尺寸变化时会通过 ResizeObserver 重新排版。
<script setup lang="ts">
import { ShowtimeTwoLineEllipsis } from 'showtime-components'
</script>
<template>
<ShowtimeTwoLineEllipsis
text="这是一段需要限制在折叠行数内展示的正文,超出部分会在末行继续省略。"
:line-count="3"
:show-ellipsis="false"
more-text="查看详情"
more-href="/detail"
@more="({ href }) => console.log(href)"
>
<template #more="{ text, openMore }">
<button type="button" @click="openMore">{{ text }}</button>
</template>
</ShowtimeTwoLineEllipsis>
</template>| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| text | 要测量并拆分的正文 | '' |
| lineCount | 折叠态最多显示的行数,小于 1 的值按 1 处理 | 2 |
| showEllipsis | 是否在折叠态末行显示省略号;关闭后只裁切,不显示 ... | true |
| expanded | 展开状态,支持 v-model:expanded | false |
| moreText | 默认“更多”入口文案,也会传给 more 插槽 | 更多>> |
| collapseText | 展开后默认“收起”入口文案 | 收起 |
| moreHref | 默认入口的链接地址 | # |
| lineHeight | 单行高度,数字按 px 处理 | 28 |
| moreGap | 末行正文与入口的间距,数字按 px 处理 | 12 |
more 事件返回 { href, event };点击默认入口或调用 more 插槽的 openMore 后会展示全部正文,并发出 update:expanded。展开后默认把“收起”作为正文后的行内入口,空间不足时自然换行;也可以使用 collapse 插槽或 closeMore 方法自定义位置。more 插槽接收 { text, href, hasOverflow, expanded, lineCount, openMore, closeMore }。默认 # 链接会阻止页面跳回顶部,传入真实地址时仍保留原生链接行为。完整说明见 多行省略。
ShowtimeBottomSheet
一个支持可配置吸附点列表的移动端底部弹层组件,默认仍提供 peek / half / full 三档体验。
完整 Props(ShowtimeBottomSheetProps)
| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| snap | 当前吸附点 | peek |
| snapPoints | 推荐传数组 [{ key, position }],兼容 { peek, half, full } 对象写法 | 默认三档数组 |
| minDragDistance | 触发切换的最小拖动距离 | 46 |
| snapSettleTolerance | 松手位置接近 snap 时直接吸附的容差 | 10 |
| contentClass | 追加到面板根节点上的类名 | '' |
| headerClass | 追加到 header 插槽容器上的类名 | '' |
| bodyClass | 追加到默认内容容器上的类名 | '' |
| entranceAnimation | 是否启用首次入场动画 | true |
| entranceOffset | 首次入场上浮偏移量,单位 px | 14 |
| entranceDuration | 首次入场动画时长,单位 ms | 260 |
| snapAnimation | 是否启用 snap 切换动画 | true |
| snapAnimationStiffness | snap 弹簧动画刚度,值越大越利落 | 420 |
| snapAnimationDamping | snap 弹簧动画阻尼,值越大越稳 | 36 |
| snapAnimationMass | snap 弹簧动画质量,值越大越有惯性 | 0.9 |
| headerDragOnly | 是否只允许顶部区域触发拖拽;开启时会关闭内容区边界联动 | true |
| handleVisible | 是否显示默认拖拽把手 | true |
| handleWidth | 默认拖拽把手宽度,单位 px | 62 |
| handleHeight | 默认拖拽把手高度,单位 px | 8 |
| panelBackground | 面板背景色 | #ffffff |
| panelRadius | 面板顶部圆角半径,单位 px | 34 |
| contentEdgeSnap | 是否允许内容区边界继续推动 sheet 连续移动(仅在 headerDragOnly=false 时生效) | true |
| contentEdgeSnapThreshold | 内容区边界联动触发阈值,单位 px | 26 |
事件
| 事件 | 说明 |
| --- | --- |
| update:snap | v-model:snap 更新 |
| snap-change | 吸附点变化时触发 |
| drag | 顶部拖拽过程中持续触发,返回 { y, movementY, isDragging } |
| content-touchstart | 内容区 touchstart 原生事件透传 |
| content-touchmove | 内容区 touchmove 原生事件透传 |
| content-touchend | 内容区 touchend 原生事件透传 |
| content-touchcancel | 内容区 touchcancel 原生事件透传 |
| content-wheel | 内容区 wheel 原生事件透传 |
特点
- 推荐 API:
snapPoints使用{ key, position }[] - 兼容 API:旧版
{ peek, half, full }对象仍然可用 - 直接拖拽和内容区边界联动都会在松手后吸附到最近的 snap point
- 当
headerDragOnly开启时,内容区只保留原生滚动和事件透传,不再触发边界联动 - 内容区边界联动会从事件目标向上查找真正可由用户滚动的容器
- 只有
overflow-y: auto/scroll/overlay的溢出元素会被当成滚动容器,overflow-y: hidden/visible/clip会被视为已经处在内容边界上 - 内容区滚动和顶部拖拽分离
- 内容区边界可继续推动 sheet 本身移动
- 可通过
drag事件实时获取当前面板的 y 轴坐标 - 可监听内容区原生
touch/wheel事件做埋点或联动
ShowtimeRevealBottomSheet
一个基于 ShowtimeBottomSheet 的高层包装组件,用来封装“头部动态 reveal 层”这类交互。
三个 Slot
| Slot | 说明 |
| --- | --- |
| reveal | 动态头部层,可以放图片、渐变、插画、视频壳或任意元素 |
| header | 前景头部内容,例如标题、副标题、操作区 |
| default | 内容区主体 |
常用 Props
| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| snap | 当前吸附点 | 继承底层 sheet 默认行为 |
| snapPoints | 透传到底层 sheet 的吸附点配置 | 无 |
| revealHeight | reveal 区高度,单位 px | 200 |
| revealSnapKeys | 允许 reveal 的 snap key 列表 | ['half', 'full'] |
| revealClass | reveal 层附加类名 | '' |
| headerClass | 前景头部附加类名 | '' |
| bodyClass | 内容区附加类名 | '' |
特点
revealslot 可以承载任意元素,而不是只支持图片- 拖拽中 reveal 层严格跟随底层 sheet 的真实
y坐标 - 即使拖拽从 reveal 区间外开始,跨过区间下边界后也会按真实
y坐标连续展开,到达上边界时完整显示 - reveal progress 大于 0 时自动隐藏默认把手,完全收起后恢复调用方的
handleVisible设置 - reveal 区间内的相邻 snap 切换共用同一份 progress,不会让头部和面板各自补间
- 松手后 reveal 会回到离散 snap 态,不会停在半开中间态
- placeholder 高度和 reveal 进度共用同一状态源,前景头部不会跳动
- 面板圆角会在非拖拽阶段柔和过渡,拖拽中关闭过渡,避免和 reveal 头部不同步
- 会继续向外透传底层的
drag、update:snap、snap-change
默认交互基线
ShowtimeRevealBottomSheet 为 reveal 场景内置了一组比底层 sheet 更合适的交互默认值:
headerDragOnly=falsecontentEdgeSnap=true
所以在常见的 quick-full -> full 头图展开流程里,组件会自行处理 reveal 连续进度和默认把手显隐。业务通常只需要按最终 snap 调整 panelRadius 或内容滚动策略,不必再按当前 snap 额外切换 headerDragOnly / contentEdgeSnap。
基础用法
<script setup lang="ts">
import { ref } from 'vue'
import {
ShowtimeRevealBottomSheet,
type ShowtimeSheetSnap
} from 'showtime-components'
const snap = ref<ShowtimeSheetSnap>('quick-full')
</script>
<template>
<ShowtimeRevealBottomSheet
v-model:snap="snap"
:snap-points="[
{ key: 'peek', position: 90 },
{ key: 'half', position: 55 },
{ key: 'quick-full', position: 30 },
{ key: 'full', position: 0 }
]"
>
<template #reveal>
<div class="hero-cover" />
</template>
<template #header>
<strong>互动留言</strong>
</template>
<div>这里是内容区域</div>
</ShowtimeRevealBottomSheet>
</template>ShowtimeActionBar
一个适合内容详情页、弹层顶部、互动区的操作栏组件。
常用参数
| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| items | 左侧互动按钮列表 | 默认内置三项 |
| followLabel | 未关注文案 | 关注 |
| followedLabel | 已关注文案 | 已关注 |
| followActive | 初始关注状态 | false |
| animated | 是否启用点击反馈动画 | true |
事件
| 事件 | 说明 |
| --- | --- |
| action | 任一按钮点击时触发,返回按钮 key |
| update:followActive | 关注状态更新 |
| follow-change | 关注状态变化时触发 |
ShowtimeUpload
统一处理图片、视频、办公文档、PDF 和常见压缩包的上传场景。组件只负责点击选择、拖拽文件、校验、裁剪、队列、进度、预览和状态管理;实际上传由 upload 属性传入的方法完成。当 limit > 1 时,会按 min(limit, maxConcurrent) 自动调度多文件上传;取消操作通过上传回调上下文中的 AbortSignal 传给业务请求。
<script setup lang="ts">
import { ref } from 'vue'
import {
ShowtimeUpload,
type ShowtimeUploadHandler,
type ShowtimeUploadItem
} from 'showtime-components'
const files = ref<ShowtimeUploadItem[]>([])
const upload: ShowtimeUploadHandler = async (file, { signal, onProgress }) => {
// 请在这里调用项目自己的上传接口,并在请求进度变化时调用 onProgress。
return { url: URL.createObjectURL(file) }
}
</script>
<template>
<ShowtimeUpload
v-model="files"
:upload="upload"
:kinds="['image', 'file']"
theme-color="#1677ff"
multiple
/>
</template>组件根节点支持拖入文件,拖拽与点击选择共享校验、裁剪和上传流程。themeColor 可统一设置内置界面的强调色;完整的上传回调类型、规则、插槽、自定义操作区和样式变量见 ShowtimeUpload。
组件库还导出无框架依赖的 TaskQueue,可用于其他支持 AbortSignal 的浏览器异步任务。它提供 FIFO 调度、并发控制、暂停、取消、清空与销毁能力;上传场景的使用方式见 ShowtimeUpload。
ShowtimeMaintenancePage
一个可用于路由页或容器内的维护状态展示组件,默认提供低干扰的亮色科技视觉和 CSS 动画;背景使用 SVG 固定网格与折线电路脉冲,可通过 theme="dark" 切换深色模式。组件不绑定业务品牌,也不会自行刷新、倒计时或跳转。
常用 Props
| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| theme | 视觉主题,可选 light 或 dark | light |
| status | 维护状态文案 | System maintenance |
| title | 主标题 | Service temporarily unavailable |
| message | 说明文案 | 内置维护提示 |
| contactLabel | 联系方式标签 | '' |
| contactValue | 联系方式内容 | '' |
| contactHref | 联系方式链接;传入后输出原生链接 | '' |
| logo / logoAlt | 可选 logo URL 与替代文本 | '' |
| illustration / illustrationAlt | 可选插画 URL 与替代文本 | '' |
| minHeight | 页面最小高度 | 100dvh |
Slots
| Slot | 说明 |
| --- | --- |
| logo | 覆盖品牌区 |
| illustration | 覆盖默认维护核心 |
| actions | 放置业务自己的返回、刷新等操作 |
基础用法
<ShowtimeMaintenancePage
theme="light"
status="Scheduled maintenance"
title="Service temporarily unavailable"
message="We are upgrading the platform. Please check back shortly."
contact-label="Support"
contact-value="[email protected]"
contact-href="mailto:[email protected]"
/>类型导出
包内也导出了常用类型:
import type {
ShowtimeActionBarProps,
ShowtimeActionItem,
ShowtimeBottomSheetDragPayload,
ShowtimeBottomSheetProps,
ShowtimeRevealBottomSheetProps,
ShowtimeMaintenancePageProps,
ShowtimeSkeletonAnimationDirection,
ShowtimeSkeletonProps,
ShowtimeSkeletonLineProps,
ShowtimeSkeletonShapeProps,
ShowtimeSkeletonVisualProps,
ShowtimeWaterfallProps,
ShowtimeTwoLineEllipsisCollapseSlotProps,
ShowtimeTwoLineEllipsisMorePayload,
ShowtimeTwoLineEllipsisMoreSlotProps,
ShowtimeTwoLineEllipsisProps,
ShowtimeSheetSnap
} from 'showtime-components'