生态产品多个设计器现已发布候选版本

查看生态总览
跳转到内容

DownloadTrigger 下载触发器 ​

用于将文本或 Blob 保存为本地文件。

用法 ​

下载文本文件

组件结构 ​

加粗的是必需部件。

data-scope="download-trigger":root

示例 ​

异步内容 ​

点击后获取下载内容

Blob ​

下载 JSON 文件

变体 ​

设置触发器外观

尺寸 ​

使用小、中、大三档尺寸

禁用 ​

禁止触发下载

设计指引 ​

何时使用 ​

  • 导出 CSV、JSON、日志或配置文件。
  • 点击后才获取或生成下载内容。

何时不用 ​

  • 文件已有稳定地址时,使用原生 <a download>。
  • 复制少量文字时,使用剪贴板。
  • 接收用户文件时,使用文件上传。

特性 ​

  • 接受字符串、Blob 与异步数据函数。
  • preparing 期间保留焦点并阻止重复触发。钮宽不变:一个 micro 之后加载环在钮正中淡入、原有内容同刻淡出留位,快速取数什么都不闪;落定后两者交叉淡回。
  • 通过完成与失败事件返回本次文件名和错误。
  • 缺省是中性淡底 subtle,只有 solid 才是品牌实心;按下有统一的缩放与换底反馈。

组合 ​

  • 与进度条组合展示可量化的长任务。
  • 通过变体与颜色调整操作层级。

最佳实践 ​

  • 文件名应包含正确扩展名。
  • 保留下载图标与可见文字;只有下载是页面主操作时才使用 solid。
  • 大文件优先使用服务端下载地址。
  • 失败事件应连接可见反馈。

反模式 ​

  • 不要将“下载已发起”等同于“文件已写入磁盘”。
  • 不要在页面加载时预先生成大文件。

API 参考 ​

产物 ​

层值
自定义元素<xh-download-trigger>
Vue 组件XhDownloadTrigger
组合式函数useDownloadTrigger
状态机downloadTriggerMachine
皮肤@xihan-ui/styles/download-trigger.css

Props ​

属性类型必填说明
dataDownloadTriggerData要下载的内容:文本、Blob,或点击时才调用的取数函数(可返回 Promise)。
fileNamestring写出的文件名;未提供或空串时回退为内建默认名。
mimeTypestring内容类型;提供后以它为准,Blob 自带的类型也按它重新包装。未提供时文本按纯文本处理。
disabledboolean禁用:按钮不可聚焦、不可点击。
variantActionVariant变体:solid / subtle / outline / ghost,默认 subtle(缺省中性淡底,solid 才品牌实心)。
toneTone颜色:brand / neutral / success / warning / danger / info。
sizeSize尺寸:sm / md / lg。
translationsPartial<DownloadTriggerTranslations>
onDownloadComplete(details: DownloadTriggerCompleteDetails) => void数据已交给浏览器时通知一次。此时只说明下载已发起,浏览器是否把文件写入磁盘组件无法感知。
onDownloadError(details: DownloadTriggerErrorDetails) => void取数失败或无法创建下载时通知;此时状态已回到 idle。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
download-completeDownloadTriggerCompleteDetails数据已交给浏览器;detail 为 { fileName }
download-errorDownloadTriggerErrorDetails取数失败或无法创建下载;detail 为 { error, fileName },此时状态已回到 idle

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhDownloadTriggerdefaultDownloadTriggerSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhDownloadTriggerchildrenSlotChildren<DownloadTriggerSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
root'idle' | 'preparing'

以下名称仅用于内部状态机。

状态:idle · preparing

事件:DOWNLOAD.TRIGGER · DOWNLOAD.SUCCESS · DOWNLOAD.ERROR · PRESS.START · PRESS.END

判据:isDisabled · canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
statusDownloadTriggerStatus
preparingboolean数据获取中。按钮不因此禁用,只是期间再次点击不会重复发起。
disabledboolean
fileNamestring本次将写出的文件名(prop 未提供时是内建默认名)。
download() => void发起一次下载意图,与点击按钮走同一路径:禁用时不生效,取数在途时不重复发起。
getRootProps() => T['button']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Spacefocus in root, 未禁用发起一次下载;取数在途时这两个键同样不会重复发起
Enter / Spaceheld in root, not disabled, not preparing按住期间投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-busy'true' | undefined
rootaria-disabled'true' | undefined
rootaria-labelprops.translations.trigger
  • 触发器使用原生 <button type="button">。
  • 准备数据时使用 aria-busy 与 aria-disabled,但不移除焦点。
  • 仅显示图标时必须提供可访问名称。

样式参考 ​

皮肤 ​

@xihan-ui/styles/download-trigger.css 按 [data-scope="download-trigger"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-download-trigger 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-loading''(条件成立时才出现)
rootdata-pressed''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-state'idle' | 'preparing'
rootdata-toneprops.tone
rootdata-variantprops.variant
rootdata-xh-action-control''
rootdata-xh-action-display'always'
rootdata-xh-action-profile'text'
rootdata-xh-action-sizeprops.size
rootdata-xh-action-variantprops.variant
rootdata-xh-ink-surface''(条件成立时才出现)
rootdata-xh-loading-ring'overlay'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-download-trigger-bgroot--xh-ink-surface
background-color
default
focus-visible
loading
xh-ink-surface
--xh-_action-variant-bg-focus-visible
--xh-_action-variant-bg-loading
--xh-_action-variant-bg-rest
download-trigger 的 root 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-download-trigger-bg-activerootbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-presseddownload-trigger 的 root 部件 background-color 覆盖槽。
--xh-download-trigger-bg-disabledroot--xh-ink-surface
background-color
disabled
xh-ink-surface
--xh-_action-variant-bg-disableddownload-trigger 的 root 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-download-trigger-bg-hoverrootbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverdownload-trigger 的 root 部件 background-color 覆盖槽。
--xh-download-trigger-borderrootborder
border-color
default
focus-visible
--xh-_action-variant-border-focus-visible
--xh-_action-variant-border-rest
download-trigger 的 root 部件 border、border-color 覆盖槽。
--xh-download-trigger-border-disabledrootborder-colordisabled--xh-_action-variant-border-disableddownload-trigger 的 root 部件 border-color 覆盖槽。
--xh-download-trigger-border-hoverrootborder-colordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-border-hover
--xh-_action-variant-border-pressed
download-trigger 的 root 部件 border-color 覆盖槽。
--xh-download-trigger-fgrootborder
border-color
color
@media (prefers-reduced-motion: reduce)
@media print
default
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
motion=reduce
not([data-disabled])
not([data-loading])
pressed
where([data-motion='reduce'])
xh-loading-ring
xh-loading-ring=overlay
--xh-_action-variant-fg-focus-visible
--xh-_action-variant-fg-hover
--xh-_action-variant-fg-loading
--xh-_action-variant-fg-pressed
--xh-_action-variant-fg-rest
download-trigger 的 root 部件 border、border-color、color 覆盖槽。
--xh-download-trigger-font-sizerootfont-sizedefault--xh-_action-profile-font-sizedownload-trigger 的 root 部件 font-size 覆盖槽。
--xh-download-trigger-font-weightrootfont-weightdefault--xh-text-label-weightdownload-trigger 的 root 部件 font-weight 覆盖槽。
--xh-download-trigger-gaprootgapdefault--xh-_action-profile-gapdownload-trigger 的 root 部件 gap 覆盖槽。
--xh-download-trigger-hrootblock-sizedefault--xh-_action-profile-visual-sizedownload-trigger 的 root 部件 block-size 覆盖槽。
--xh-download-trigger-icon-sizeroot--xh-icon-sizedefault--xh-_action-profile-glyph-sizedownload-trigger 的 root 部件 --xh-icon-size 覆盖槽。
--xh-download-trigger-loading-durationrootanimationxh-loading-ring--xh-motion-loop-spindownload-trigger 的 root 部件 animation 覆盖槽。
--xh-download-trigger-loading-fgrootborder
border-color
@media (prefers-reduced-motion: reduce)
@media print
motion=reduce
where([data-motion='reduce'])
xh-loading-ring
xh-loading-ring=overlay
--xh-download-trigger-fgdownload-trigger 的 root 部件 border、border-color 覆盖槽。
--xh-download-trigger-pxrootpadding-inlinedefault--xh-_action-profile-padding-inlinedownload-trigger 的 root 部件 padding-inline 覆盖槽。
--xh-download-trigger-radiusrootborder-radiusdefault--xh-shape-controldownload-trigger 的 root 部件 border-radius 覆盖槽。
--xh-download-trigger-shadow-hoverrootbox-shadowdisabled
hover
loading
not([data-disabled])
not([data-loading])
nonedownload-trigger 的 root 部件 box-shadow 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 循环(见动效规范)。

可覆盖的动效槽:--xh-download-trigger-loading-duration。

状态切换走 transition,属性由 transition-* 分项给定。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

响应式 ​

皮肤另按输入能力分档:pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License