Skip to content

组件:empty-state/空状态

字数
2738 字
阅读时间
13 分钟

MindGuard小程序的通用空状态展示组件,支持多种场景的空状态提示,提供友好的用户引导和操作指引。

位置与作用

出现页面

  • 今天Tab:首次使用时的心情打卡引导
  • 心情随笔Tab:暂无日记记录时的引导
  • 任务Tab:任务列表为空时的提示
  • 树洞Tab:暂无帖子时的社区引导
  • 个人中心:各功能模块为空时的状态提示
  • 所有分包页面:统一提供空状态体验

承担任务

  • 展示各种业务场景的空状态
  • 提供清晰的用户引导和操作指引
  • 支持图片、图标、文字的组合展示
  • 集成操作按钮,引导用户进行下一步行动
  • 支持不同风格和主题的空状态样式
  • 提供友好的错误提示和重试机制

Props(属性)

名称类型必填默认说明
typeString'default'空状态类型:'default' | 'data' | 'network' | 'permission' | 'search'
titleString''标题文字
descriptionString''描述文字
imageString''图片路径(本地或网络)
iconString''图标名称
actionTextString''操作按钮文字
actionTypeString'button'操作类型:'button' | 'link' | 'refresh'
showRefreshBooleanfalse是否显示刷新按钮
sizeString'medium'尺寸:'small' | 'medium' | 'large'
themeString'light'主题:'light' | 'dark'

Slots(插槽)

插槽名用途说明
image图片区域可替换默认的空状态图片或图标
title标题区域可自定义标题显示样式
description描述区域可自定义描述文字内容
action操作区域可自定义操作按钮样式
extra额外内容可添加额外的提示信息或操作

Events(事件)

事件名触发时机回调参数埋点映射
onAction用户点击操作按钮{type: 'action', actionType: string, page: string}act_empty_action
onRefresh用户点击刷新按钮{type: 'refresh', page: string, timestamp: number}act_empty_refresh
onRetry用户点击重试按钮{type: 'retry', page: string, errorType: string}act_empty_retry
onLoadMore用户点击加载更多{type: 'loadMore', page: string, context: object}act_empty_loadmore

Methods(外部可调)

方法名入参与返回使用示例
show(type: string)入参:类型;返回:voidthis.selectComponent('#empty').show('network')
hide()入参:无;返回:voidthis.selectComponent('#empty').hide()
refresh()入参:无;返回:voidthis.selectComponent('#empty').refresh()
updateConfig(config: object)入参:配置;返回:voidthis.selectComponent('#empty').updateConfig({...})
setLoading(loading: boolean)入参:加载状态;返回:voidthis.selectComponent('#empty').setLoading(true)

Data Contract(数据契约)

输入字段

字段来源服务/集合说明
type页面配置空状态类型标识
title页面配置标题文字内容
description页面配置描述文字内容
image资源文件本地图片或网络图片路径
icon图标库图标名称或路径
actionText多语言配置操作按钮文字
actionType页面配置操作行为类型
theme主题配置主题样式配置

输出/回写

字段目标集合/接口权限说明
user_events.event_typeuser_events集合空状态交互事件记录
user_behavior.first_actionanalytics集合用户首次行为分析
page_stats.empty_viewsanalytics集合页面空状态曝光统计

视觉与交互(对齐样式规范)

尺寸与间距

  • 组件容器:宽度 100%,最小高度 400rpx
  • 图片区域:图片最大宽度 320rpx,高度自适应
  • 内容区域:左右边距 48rpx,上下边距 48rpx
  • 标题文字:字体大小 32rpx,行高 44rpx
  • 描述文字:字体大小 28rpx,行高 40rpx
  • 按钮尺寸:最小高度 88rpx,左右内边距 48rpx

颜色(Token映射)

元素Token色值用途
组件背景--color-ink-0#F7F9FC组件主体背景
标题文字--color-ink-900#2C3640主要标题文字
描述文字--color-ink-600#5A6672次要描述文字
按钮主色--color-brand-500#3A7BD5主要操作按钮
按钮次色--color-ink-600#5A6672次要操作按钮
图标颜色--color-ink-400#8B95A7图标和装饰元素
分割线--color-ink-100#E9EDF3内容分割线

状态变化

  • normal: 默认状态,正常显示空状态内容
  • loading: 加载状态,显示加载动画
  • error: 错误状态,显示错误提示和重试按钮
  • refreshing: 刷新状态,显示刷新动画
  • success: 成功状态,显示成功提示(短暂显示后跳转)

可访问性

  • 对比度: 所有文本对比度 ≥ 4.5:1,确保清晰可读
  • 按钮尺寸: 所有可点击元素 ≥ 88×88rpx,符合微信小程序规范
  • 文字替代: 所有图片和图标都有对应的文字说明
  • 屏幕阅读器: 完整的ARIA标签,描述空状态的意义和操作

性能与包体

性能优化

  • 图片懒加载: 网络图片使用懒加载,避免首屏压力
  • 图标优化: 优先使用字体图标,减少包体体积
  • 状态缓存: 空状态配置缓存,避免重复计算
  • 事件防抖: 刷新和重试按钮使用防抖,避免重复操作

包体控制

  • 主包归属: 位于主包,为所有页面提供空状态展示
  • 资源优化: 空状态图片使用webp格式,减少体积
  • 按需加载: 复杂动画效果按需加载
  • 代码压缩: 组件代码已经过压缩和优化

埋点(来自数据分析需求)

场景事件名参数
空状态曝光exp_empty_statepagePath, emptyType, scene, timestamp
操作按钮点击act_empty_actionpagePath, actionType, buttonText, emptyType
刷新按钮点击act_empty_refreshpagePath, refreshType, emptyType
重试按钮点击act_empty_retrypagePath, errorType, retryCount
加载更多点击act_empty_loadmorepagePath, loadContext, emptyType

测试要点

单测

  • 类型测试: 验证不同空状态类型的正确显示
  • 事件测试: 验证各种用户交互事件的正确触发
  • 样式测试: 验证不同主题和尺寸配置的正确显示
  • 图片测试: 验证本地和网络图片的正确加载

E2E测试

  • 引导流程: 首次用户的完整引导流程
  • 错误恢复: 网络异常、权限问题的恢复流程
  • 操作转化: 空状态到功能页面的转化率
  • 重试机制: 各种重试场景的功能验证

边界测试

  • 超长文本: 标题和描述文字超长的处理
  • 无数据: 完全无数据时的显示效果
  • 快速操作: 连续点击操作按钮的处理
  • 弱网环境: 弱网下的图片加载和显示

示例(WXML/WXSS 片段)

WXML 使用示例

xml
<!-- 基础使用 -->
<empty-state
  type="data"
  title="暂无数据"
  description="还没有相关内容,快来创建第一条记录吧!"
  action-text="立即创建"
  bind:action="onCreateAction"
/>

<!-- 完整配置 -->
<empty-state
  id="empty-state"
  type="network"
  title="网络连接失败"
  description="请检查网络设置后重试"
  image="/assets/images/empty-network.png"
  action-text="重新连接"
  show-refresh="{{true}}"
  size="large"
  theme="light"
  bind:action="onRetryAction"
  bind:refresh="onRefresh"
>
  <!-- 自定义图片 -->
  <view slot="image" class="custom-image">
    <image src="/assets/images/custom-empty.png" mode="aspectFit" />
  </view>

  <!-- 自定义标题 -->
  <view slot="title" class="custom-title">
    <text>自定义标题</text>
  </view>

  <!-- 自定义描述 -->
  <view slot="description" class="custom-description">
    <text>这是自定义的描述文字内容</text>
    <text>可以包含更多的详细信息</text>
  </view>

  <!-- 自定义操作 -->
  <view slot="action" class="custom-action">
    <button class="primary-btn" bindtap="onPrimaryAction">主要操作</button>
    <button class="secondary-btn" bindtap="onSecondaryAction">次要操作</button>
  </view>
</empty-state>

WXSS 样式示例

scss
/* 组件基础样式 */
.empty-state {
  width: 100%;
  min-height: 400rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48rpx;
  background: var(--color-ink-0);
  transition: all 0.3s ease;
}

/* 图片区域 */
.empty-state-image {
  width: 240rpx;
  height: 240rpx;
  margin-bottom: 32rpx;
  position: relative;
}

.empty-state-image image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.empty-state-icon {
  width: 120rpx;
  height: 120rpx;
  margin-bottom: 32rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-state-icon image {
  width: 100%;
  height: 100%;
}

/* 内容区域 */
.empty-state-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: 540rpx;
}

.empty-state-title {
  font-size: 32rpx;
  font-weight: 500;
  color: var(--color-ink-900);
  line-height: 44rpx;
  margin-bottom: 16rpx;
  text-align: center;
}

.empty-state-description {
  font-size: 28rpx;
  color: var(--color-ink-600);
  line-height: 40rpx;
  text-align: center;
  margin-bottom: 32rpx;
}

/* 操作区域 */
.empty-state-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16rpx;
  width: 100%;
  max-width: 400rpx;
}

.empty-state-button {
  width: 100%;
  height: 88rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 44rpx;
  font-size: 28rpx;
  font-weight: 500;
  transition: all 0.3s ease;
}

.empty-state-button.primary {
  background: var(--color-brand-500);
  color: white;
}

.empty-state-button.primary:hover {
  background: var(--color-brand-600);
  transform: translateY(-2rpx);
}

.empty-state-button.secondary {
  background: transparent;
  color: var(--color-brand-500);
  border: 2rpx solid var(--color-brand-500);
}

.empty-state-button.secondary:hover {
  background: var(--color-brand-50);
}

/* 刷新按钮 */
.empty-state-refresh {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 88rpx;
  height: 88rpx;
  border-radius: 50%;
  background: var(--color-brand-50);
  margin-top: 24rpx;
  transition: all 0.3s ease;
}

.empty-state-refresh:hover {
  background: var(--color-brand-100);
  transform: scale(1.05);
}

.empty-state-refresh-icon {
  width: 40rpx;
  height: 40rpx;
}

/* 加载状态 */
.empty-state.loading .empty-state-image {
  animation: pulse 2s ease-in-out infinite;
}

.empty-state.loading .empty-state-refresh-icon {
  animation: rotate 1s linear infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

@keyframes rotate {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* 尺寸变体 */
.empty-state.small {
  min-height: 300rpx;
  padding: 32rpx;
}

.empty-state.small .empty-state-image {
  width: 160rpx;
  height: 160rpx;
  margin-bottom: 24rpx;
}

.empty-state.small .empty-state-title {
  font-size: 28rpx;
  line-height: 40rpx;
}

.empty-state.small .empty-state-description {
  font-size: 24rpx;
  line-height: 36rpx;
}

.empty-state.large {
  min-height: 500rpx;
  padding: 64rpx;
}

.empty-state.large .empty-state-image {
  width: 320rpx;
  height: 320rpx;
  margin-bottom: 40rpx;
}

.empty-state.large .empty-state-title {
  font-size: 36rpx;
  line-height: 48rpx;
}

.empty-state.large .empty-state-description {
  font-size: 32rpx;
  line-height: 44rpx;
}

/* 主题适配 */
.empty-state.dark {
  background: var(--color-ink-900);
}

.empty-state.dark .empty-state-title {
  color: var(--color-ink-0);
}

.empty-state.dark .empty-state-description {
  color: var(--color-ink-300);
}

.empty-state.dark .empty-state-button.secondary {
  color: var(--color-brand-400);
  border-color: var(--color-brand-400);
}

.empty-state.dark .empty-state-button.secondary:hover {
  background: var(--color-brand-900);
}

/* 错误状态 */
.empty-state.error .empty-state-image {
  animation: shake 0.5s ease-in-out;
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-10rpx); }
  75% { transform: translateX(10rpx); }
}

/* 成功状态 */
.empty-state.success .empty-state-image {
  animation: success-bounce 0.6s ease-out;
}

@keyframes success-bounce {
  0% { transform: scale(1); }
  50% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

版本与变更记录

版本历史

  • v1.0.0 (2025-09-22): 初始版本,支持基本空状态展示
  • v1.1.0 (计划): 支持更多场景类型和自定义样式
  • v1.2.0 (计划): 添加动画效果和交互反馈
  • v2.0.0 (计划): 支持智能推荐和个性化空状态

变更说明

  • v1.0.0: 实现基础空状态功能,支持多种场景类型
  • v1.1.0: 增加更多场景支持,提供更丰富的自定义选项
  • v1.2.0: 添加动画效果,提升用户体验和交互反馈
  • v2.0.0: 支持AI智能推荐,根据用户行为展示个性化空状态

组件维护者: MindGuard前端团队 最后更新: 2025-09-22 相关文档: 状态管理规范, 用户体验设计

贡献者

The avatar of contributor named as Cai Hongyu Cai Hongyu

文件历史

撰写