Skip to content

状态组件

状态组件提供了各种状态展示功能,包括空状态等场景的处理。

导入

typescript
import { DuxBlockEmpty } from '@duxweb/dvha-pro'

组件总览

DVHA Pro 提供以下状态组件:

  • DuxBlockEmpty - 空状态组件

DuxBlockEmpty 空状态组件

空状态组件,用于在数据为空或无内容时显示友好的提示信息,支持简单和详细两种显示模式。

属性

属性名类型默认值说明
textstring-主要提示文本
descstring-描述文本
simplebooleanfalse是否使用简单模式(垂直布局)

基础用法

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
</script>

<template>
  <!-- 默认空状态 -->
  <DuxBlockEmpty />

  <!-- 自定义文本 -->
  <DuxBlockEmpty
    text="暂无数据"
    desc="当前没有任何内容,请稍后再试"
  />

  <!-- 简单模式 -->
  <DuxBlockEmpty
    text="空空如也"
    simple
  />
</template>

在列表中使用

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const dataList = ref([])
const isLoading = ref(false)
</script>

<template>
  <div class="min-h-[400px] flex flex-col">
    <!-- 数据列表 -->
    <div v-if="dataList.length > 0" class="flex-1">
      <div
        v-for="item in dataList"
        :key="item.id"
        class="p-4 border-b"
      >
        {{ item.name }}
      </div>
    </div>

    <!-- 空状态 -->
    <div v-else-if="!isLoading" class="flex-1 flex items-center justify-center">
      <DuxBlockEmpty
        text="暂无数据"
        desc="当前列表为空,请添加一些内容"
      />
    </div>

    <!-- 加载状态 -->
    <div v-else class="flex-1 flex items-center justify-center">
      <div class="text-muted">
        加载中...
      </div>
    </div>
  </div>
</template>

在表格中使用

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
import { NDataTable } from 'naive-ui'
import { ref } from 'vue'

const tableData = ref([])
const columns = [
  { title: '姓名', key: 'name' },
  { title: '邮箱', key: 'email' },
  { title: '状态', key: 'status' }
]
</script>

<template>
  <NDataTable
    :columns="columns"
    :data="tableData"
    :loading="false"
  >
    <template #empty>
      <DuxBlockEmpty
        text="暂无记录"
        desc="表格中没有数据,请尝试添加一些记录"
      />
    </template>
  </NDataTable>
</template>

在卡片网格中使用

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
import { NButton, NCard } from 'naive-ui'
import { ref } from 'vue'

const cardList = ref([])

function addCard() {
  cardList.value.push({
    id: Date.now(),
    title: `卡片 ${cardList.value.length + 1}`,
    content: '这是卡片内容'
  })
}

function clearCards() {
  cardList.value = []
}
</script>

<template>
  <div class="space-y-4">
    <!-- 操作按钮 -->
    <div class="flex gap-2">
      <NButton type="primary" @click="addCard">
        添加卡片
      </NButton>
      <NButton @click="clearCards">
        清空卡片
      </NButton>
    </div>

    <!-- 卡片网格 -->
    <div v-if="cardList.length > 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
      <NCard
        v-for="card in cardList"
        :key="card.id"
        :title="card.title"
        size="small"
      >
        {{ card.content }}
      </NCard>
    </div>

    <!-- 空状态 -->
    <div v-else class="min-h-[300px] flex items-center justify-center">
      <DuxBlockEmpty
        text="暂无卡片"
        desc="点击上方按钮添加一些卡片内容"
      />
    </div>
  </div>
</template>

搜索结果为空

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
import { NButton, NInput } from 'naive-ui'
import { computed, ref } from 'vue'

const searchKeyword = ref('')
const allData = ref([
  { id: 1, name: '苹果', category: '水果' },
  { id: 2, name: '香蕉', category: '水果' },
  { id: 3, name: '胡萝卜', category: '蔬菜' }
])

const filteredData = computed(() => {
  if (!searchKeyword.value)
    return allData.value
  return allData.value.filter(item =>
    item.name.includes(searchKeyword.value)
    || item.category.includes(searchKeyword.value)
  )
})

function clearSearch() {
  searchKeyword.value = ''
}
</script>

<template>
  <div class="space-y-4">
    <!-- 搜索框 -->
    <NInput
      v-model:value="searchKeyword"
      placeholder="搜索商品名称或分类..."
      clearable
    />

    <!-- 搜索结果 -->
    <div v-if="filteredData.length > 0" class="space-y-2">
      <div
        v-for="item in filteredData"
        :key="item.id"
        class="p-3 bg-gray-50 rounded"
      >
        <div class="font-medium">
          {{ item.name }}
        </div>
        <div class="text-sm text-gray-500">
          {{ item.category }}
        </div>
      </div>
    </div>

    <!-- 搜索为空 -->
    <div v-else-if="searchKeyword" class="min-h-[200px] flex items-center justify-center">
      <DuxBlockEmpty
        text="未找到相关结果"
        desc="尝试使用不同的关键词搜索"
      >
        <template #action>
          <NButton @click="clearSearch">
            清空搜索
          </NButton>
        </template>
      </DuxBlockEmpty>
    </div>

    <!-- 初始状态 -->
    <div v-else class="min-h-[200px] flex items-center justify-center">
      <DuxBlockEmpty
        text="开始搜索"
        desc="在上方输入框中输入关键词进行搜索"
        simple
      />
    </div>
  </div>
</template>

不同显示模式对比

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
</script>

<template>
  <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
    <!-- 标准模式 -->
    <div class="space-y-4">
      <h3 class="text-lg font-medium">
        标准模式
      </h3>
      <div class="min-h-[200px] border rounded-lg flex items-center justify-center">
        <DuxBlockEmpty
          text="暂无内容"
          desc="这里使用标准的水平布局模式"
        />
      </div>
    </div>

    <!-- 简单模式 -->
    <div class="space-y-4">
      <h3 class="text-lg font-medium">
        简单模式
      </h3>
      <div class="min-h-[200px] border rounded-lg flex items-center justify-center">
        <DuxBlockEmpty
          text="暂无内容"
          simple
        />
      </div>
    </div>
  </div>
</template>

在不同容器中的适配

vue
<script setup>
import { DuxBlockEmpty } from '@duxweb/dvha-pro'
import { NCard } from 'naive-ui'
</script>

<template>
  <div class="space-y-6">
    <!-- 小容器 -->
    <div class="space-y-2">
      <h4 class="font-medium">
        小容器(高度 150px)
      </h4>
      <div class="h-[150px] border rounded flex items-center justify-center">
        <DuxBlockEmpty text="无数据" simple />
      </div>
    </div>

    <!-- 中等容器 -->
    <div class="space-y-2">
      <h4 class="font-medium">
        中等容器(高度 250px)
      </h4>
      <div class="h-[250px] border rounded flex items-center justify-center">
        <DuxBlockEmpty
          text="暂无数据"
          desc="请添加一些内容"
        />
      </div>
    </div>

    <!-- 大容器 -->
    <div class="space-y-2">
      <h4 class="font-medium">
        大容器(高度 400px)
      </h4>
      <div class="h-[400px] border rounded flex items-center justify-center">
        <DuxBlockEmpty
          text="这里空空如也"
          desc="看起来这里还没有任何内容,您可以开始添加一些数据或内容来填充这个区域"
        />
      </div>
    </div>

    <!-- 卡片容器 -->
    <div class="space-y-2">
      <h4 class="font-medium">
        卡片容器
      </h4>
      <NCard title="数据列表" size="small">
        <div class="min-h-[200px] flex items-center justify-center">
          <DuxBlockEmpty
            text="列表为空"
            desc="当前没有任何数据项"
          />
        </div>
      </NCard>
    </div>
  </div>
</template>

设计特性

视觉设计

  • 友好的图标:使用精心设计的 SVG 图标,支持主题色彩适配
  • 动态效果:图标包含微妙的动画效果,提升用户体验
  • 响应式适配:自动适应不同尺寸的容器
  • 主题集成:完美集成 DVHA Pro 的设计系统

布局模式

  • 水平布局:图标和文本水平排列,适合较宽的容器
  • 垂直布局:图标和文本垂直排列,适合较窄或较小的容器
  • 自适应:根据容器大小自动选择最佳布局

最佳实践

何时使用

  • 列表、表格、网格等容器中没有数据时
  • 搜索结果为空时
  • 加载完成但内容为空时
  • 用户首次进入某个功能模块时

文案建议

  • 简洁明了:使用简短、清晰的文案
  • 积极引导:提供下一步操作的建议
  • 符合场景:根据具体业务场景定制文案
vue
<!-- 好的文案示例 -->
<DuxBlockEmpty
  text="暂无文章"
  desc="开始创建您的第一篇文章吧"
/>

<!-- 避免的文案示例 -->
<DuxBlockEmpty
  text="没有数据"
  desc="数据为空"
/>

容器适配

vue
<!-- 小容器使用简单模式 -->
<div class="h-32">
  <DuxBlockEmpty text="无内容" simple />
</div>

<!-- 大容器使用标准模式 -->
<div class="min-h-[300px]">
  <DuxBlockEmpty
    text="暂无数据"
    desc="详细的描述信息"
  />
</div>

常见问题

如何自定义空状态图标?

目前组件使用内置的 SVG 图标,如需自定义,可以通过 CSS 覆盖或创建自定义组件:

vue
<script setup>
import { defineComponent } from 'vue'

const CustomEmpty = defineComponent({
  setup() {
    return () => (
      <div class="flex flex-col items-center gap-4">
        <div class="w-16 h-16">
          <!-- 自定义图标 -->
          <img src="/custom-empty-icon.svg" alt="空状态" />
        </div>
        <div class="text-center">
          <div class="text-lg">自定义空状态</div>
          <div class="text-sm text-muted">这是自定义的空状态组件</div>
        </div>
      </div>
    )
  }
})
</script>

如何在空状态中添加操作按钮?

可以在空状态组件外层添加操作按钮:

vue
<div class="flex flex-col items-center gap-4">
  <DuxBlockEmpty
    text="暂无数据"
    desc="还没有任何内容"
  />
  <NButton type="primary" @click="handleAdd">
    添加内容
  </NButton>
</div>

空状态组件是否支持国际化?

组件本身不内置国际化,但可以通过传入对应语言的文本实现:

vue
<script setup>
import { useI18n } from '@duxweb/dvha-core'

const { t } = useI18n()
</script>

<template>
  <DuxBlockEmpty
    :text="t('common.empty.title')"
    :desc="t('common.empty.description')"
  />
</template>