Statistic 统计组件 
概述 
Statistic 统计组件是 Element Plus 提供的一个用于展示统计数值的组件。它能够突出显示某个统计数值,支持设置数值精度、前缀、后缀等,常用于数据大屏、仪表板、统计报表等场景。
学习目标 
通过本文档的学习,你将掌握:
- Statistic 统计组件的基本概念和使用场景
- 基础用法和数值格式化
- 前缀、后缀和自定义内容
- 数值动画和加载状态
- 实际项目中的应用示例
- 完整的 API 文档和最佳实践
基础用法 
基础统计数值 
最简单的统计数值展示:
vue
<template>
  <el-row :gutter="20">
    <el-col :span="6">
      <el-statistic title="用户总数" :value="268500" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="账户余额" :value="268500" precision="2" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="活跃用户" :value="268500" suffix="人" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="转化率" :value="0.85" suffix="%" :precision="2" />
    </el-col>
  </el-row>
</template>设置数值精度 
通过 precision 属性设置数值的小数位数:
vue
<template>
  <el-row :gutter="20">
    <el-col :span="8">
      <el-statistic title="精度为0" :value="268500" :precision="0" />
    </el-col>
    <el-col :span="8">
      <el-statistic title="精度为2" :value="268500.123" :precision="2" />
    </el-col>
    <el-col :span="8">
      <el-statistic title="精度为4" :value="268500.123456" :precision="4" />
    </el-col>
  </el-row>
</template>前缀和后缀 
使用 prefix 和 suffix 属性添加前缀和后缀:
vue
<template>
  <el-row :gutter="20">
    <el-col :span="6">
      <el-statistic title="销售额" :value="268500" prefix="¥" :precision="2" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="用户数" :value="268500" suffix="人" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="增长率" :value="85.6" prefix="+" suffix="%" :precision="1" />
    </el-col>
    <el-col :span="6">
      <el-statistic title="下载量" :value="268500" suffix="次" />
    </el-col>
  </el-row>
</template>使用插槽自定义内容 
通过插槽可以自定义标题、数值和前后缀的显示:
vue
<template>
  <el-row :gutter="20">
    <el-col :span="12">
      <el-statistic :value="268500">
        <template #title>
          <div style="display: inline-flex; align-items: center">
            <el-icon style="margin-right: 4px">
              <User />
            </el-icon>
            用户总数
          </div>
        </template>
        <template #suffix>
          <span style="color: #409eff">人</span>
        </template>
      </el-statistic>
    </el-col>
    <el-col :span="12">
      <el-statistic title="销售额" :value="268500">
        <template #prefix>
          <el-icon style="color: #67c23a">
            <Money />
          </el-icon>
        </template>
        <template #suffix>
          <span style="color: #67c23a">元</span>
        </template>
      </el-statistic>
    </el-col>
  </el-row>
</template>
<script setup>
import { User, Money } from '@element-plus/icons-vue'
</script>数值格式化 
使用 formatter 属性自定义数值格式化:
vue
<template>
  <el-row :gutter="20">
    <el-col :span="8">
      <el-statistic 
        title="千分位格式" 
        :value="268500" 
        :formatter="(value) => value.toLocaleString()"
      />
    </el-col>
    <el-col :span="8">
      <el-statistic 
        title="文件大小" 
        :value="1024000" 
        :formatter="formatFileSize"
      />
    </el-col>
    <el-col :span="8">
      <el-statistic 
        title="时间格式" 
        :value="3661" 
        :formatter="formatTime"
      />
    </el-col>
  </el-row>
</template>
<script setup>
const formatFileSize = (value) => {
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let size = value
  let unitIndex = 0
  
  while (size >= 1024 && unitIndex < units.length - 1) {
    size /= 1024
    unitIndex++
  }
  
  return `${size.toFixed(2)} ${units[unitIndex]}`
}
const formatTime = (value) => {
  const hours = Math.floor(value / 3600)
  const minutes = Math.floor((value % 3600) / 60)
  const seconds = value % 60
  
  return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}
</script>加载状态 
通过 loading 属性显示加载状态:
vue
<template>
  <div>
    <el-button @click="toggleLoading" style="margin-bottom: 20px">
      {{ loading ? '停止加载' : '开始加载' }}
    </el-button>
    
    <el-row :gutter="20">
      <el-col :span="6">
        <el-statistic title="用户总数" :value="268500" :loading="loading" />
      </el-col>
      <el-col :span="6">
        <el-statistic title="销售额" :value="268500" prefix="¥" :loading="loading" />
      </el-col>
      <el-col :span="6">
        <el-statistic title="订单数" :value="1680" suffix="单" :loading="loading" />
      </el-col>
      <el-col :span="6">
        <el-statistic title="转化率" :value="85.6" suffix="%" :loading="loading" />
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref } from 'vue'
const loading = ref(false)
const toggleLoading = () => {
  loading.value = !loading.value
}
</script>实际应用示例 
数据大屏统计面板 
vue
<template>
  <div class="dashboard">
    <h2>数据大屏统计</h2>
    
    <el-row :gutter="20" class="stats-row">
      <el-col :span="6">
        <el-card class="stat-card">
          <el-statistic 
            title="今日访问量" 
            :value="todayVisits" 
            :loading="loading"
            :formatter="(value) => value.toLocaleString()"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><View /></el-icon>
                <span>今日访问量</span>
              </div>
            </template>
            <template #suffix>
              <span class="trend-up">↗ +12.5%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="stat-card">
          <el-statistic 
            title="总销售额" 
            :value="totalSales" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><Money /></el-icon>
                <span>总销售额</span>
              </div>
            </template>
            <template #prefix>
              <span class="currency">¥</span>
            </template>
            <template #suffix>
              <span class="trend-up">↗ +8.3%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="stat-card">
          <el-statistic 
            title="新增用户" 
            :value="newUsers" 
            :loading="loading"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><UserFilled /></el-icon>
                <span>新增用户</span>
              </div>
            </template>
            <template #suffix>
              <span class="trend-down">↘ -2.1%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="stat-card">
          <el-statistic 
            title="转化率" 
            :value="conversionRate" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><TrendCharts /></el-icon>
                <span>转化率</span>
              </div>
            </template>
            <template #suffix>
              <span>%</span>
              <span class="trend-up">↗ +1.2%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
    </el-row>
    
    <el-row :gutter="20" class="stats-row">
      <el-col :span="8">
        <el-card class="stat-card">
          <el-statistic 
            title="服务器响应时间" 
            :value="responseTime" 
            :loading="loading"
            :formatter="formatResponseTime"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><Timer /></el-icon>
                <span>服务器响应时间</span>
              </div>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="8">
        <el-card class="stat-card">
          <el-statistic 
            title="存储使用量" 
            :value="storageUsed" 
            :loading="loading"
            :formatter="formatFileSize"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><FolderOpened /></el-icon>
                <span>存储使用量</span>
              </div>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="8">
        <el-card class="stat-card">
          <el-statistic 
            title="在线用户" 
            :value="onlineUsers" 
            :loading="loading"
          >
            <template #title>
              <div class="stat-title">
                <el-icon><Connection /></el-icon>
                <span>在线用户</span>
              </div>
            </template>
            <template #suffix>
              <span class="online-indicator">●</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
    </el-row>
    
    <div class="refresh-btn">
      <el-button type="primary" @click="refreshData" :loading="loading">
        刷新数据
      </el-button>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { 
  View, Money, UserFilled, TrendCharts, 
  Timer, FolderOpened, Connection 
} from '@element-plus/icons-vue'
const loading = ref(false)
const todayVisits = ref(0)
const totalSales = ref(0)
const newUsers = ref(0)
const conversionRate = ref(0)
const responseTime = ref(0)
const storageUsed = ref(0)
const onlineUsers = ref(0)
const formatResponseTime = (value) => {
  return `${value} ms`
}
const formatFileSize = (value) => {
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let size = value
  let unitIndex = 0
  
  while (size >= 1024 && unitIndex < units.length - 1) {
    size /= 1024
    unitIndex++
  }
  
  return `${size.toFixed(2)} ${units[unitIndex]}`
}
const refreshData = async () => {
  loading.value = true
  
  // 模拟 API 请求
  await new Promise(resolve => setTimeout(resolve, 1500))
  
  // 模拟数据更新
  todayVisits.value = Math.floor(Math.random() * 100000) + 50000
  totalSales.value = Math.floor(Math.random() * 1000000) + 500000
  newUsers.value = Math.floor(Math.random() * 5000) + 1000
  conversionRate.value = Math.random() * 10 + 85
  responseTime.value = Math.floor(Math.random() * 100) + 50
  storageUsed.value = Math.floor(Math.random() * 1024 * 1024 * 1024) + 1024 * 1024 * 500
  onlineUsers.value = Math.floor(Math.random() * 1000) + 200
  
  loading.value = false
}
// 初始加载数据
onMounted(() => {
  refreshData()
})
</script>
<style scoped>
.dashboard {
  padding: 20px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  min-height: 100vh;
}
.dashboard h2 {
  color: white;
  text-align: center;
  margin-bottom: 30px;
  font-size: 28px;
}
.stats-row {
  margin-bottom: 20px;
}
.stat-card {
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stat-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.stat-title {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #606266;
  font-weight: 500;
}
.stat-title .el-icon {
  font-size: 18px;
  color: #409eff;
}
.currency {
  color: #67c23a;
  font-weight: bold;
}
.trend-up {
  color: #67c23a;
  font-size: 12px;
  margin-left: 8px;
}
.trend-down {
  color: #f56c6c;
  font-size: 12px;
  margin-left: 8px;
}
.online-indicator {
  color: #67c23a;
  font-size: 8px;
  margin-left: 4px;
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.5; }
  100% { opacity: 1; }
}
.refresh-btn {
  text-align: center;
  margin-top: 30px;
}
:deep(.el-statistic__content) {
  font-size: 28px;
  font-weight: bold;
  color: #303133;
}
:deep(.el-statistic__head) {
  margin-bottom: 12px;
}
</style>电商销售统计 
vue
<template>
  <div class="sales-dashboard">
    <div class="header">
      <h3>销售数据统计</h3>
      <el-date-picker
        v-model="dateRange"
        type="daterange"
        range-separator="至"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
        @change="handleDateChange"
      />
    </div>
    
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card class="metric-card">
          <el-statistic 
            title="总订单数" 
            :value="metrics.totalOrders" 
            :loading="loading"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><Document /></el-icon>
                总订单数
              </div>
            </template>
            <template #suffix>
              <el-tag :type="metrics.ordersGrowth >= 0 ? 'success' : 'danger'" size="small">
                {{ metrics.ordersGrowth >= 0 ? '+' : '' }}{{ metrics.ordersGrowth }}%
              </el-tag>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="metric-card">
          <el-statistic 
            title="总销售额" 
            :value="metrics.totalRevenue" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><Money /></el-icon>
                总销售额
              </div>
            </template>
            <template #prefix>
              <span class="currency">¥</span>
            </template>
            <template #suffix>
              <el-tag :type="metrics.revenueGrowth >= 0 ? 'success' : 'danger'" size="small">
                {{ metrics.revenueGrowth >= 0 ? '+' : '' }}{{ metrics.revenueGrowth }}%
              </el-tag>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="metric-card">
          <el-statistic 
            title="平均客单价" 
            :value="metrics.avgOrderValue" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><Wallet /></el-icon>
                平均客单价
              </div>
            </template>
            <template #prefix>
              <span class="currency">¥</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="6">
        <el-card class="metric-card">
          <el-statistic 
            title="转化率" 
            :value="metrics.conversionRate" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><TrendCharts /></el-icon>
                转化率
              </div>
            </template>
            <template #suffix>
              <span>%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
    </el-row>
    
    <el-row :gutter="20" style="margin-top: 20px">
      <el-col :span="8">
        <el-card class="metric-card">
          <el-statistic 
            title="新客户数" 
            :value="metrics.newCustomers" 
            :loading="loading"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><UserFilled /></el-icon>
                新客户数
              </div>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="8">
        <el-card class="metric-card">
          <el-statistic 
            title="退款率" 
            :value="metrics.refundRate" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><RefreshLeft /></el-icon>
                退款率
              </div>
            </template>
            <template #suffix>
              <span>%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
      
      <el-col :span="8">
        <el-card class="metric-card">
          <el-statistic 
            title="复购率" 
            :value="metrics.repeatPurchaseRate" 
            :loading="loading"
            :precision="2"
          >
            <template #title>
              <div class="metric-title">
                <el-icon><Refresh /></el-icon>
                复购率
              </div>
            </template>
            <template #suffix>
              <span>%</span>
            </template>
          </el-statistic>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { 
  Document, Money, Wallet, TrendCharts, 
  UserFilled, RefreshLeft, Refresh 
} from '@element-plus/icons-vue'
const loading = ref(false)
const dateRange = ref([])
const metrics = reactive({
  totalOrders: 0,
  totalRevenue: 0,
  avgOrderValue: 0,
  conversionRate: 0,
  newCustomers: 0,
  refundRate: 0,
  repeatPurchaseRate: 0,
  ordersGrowth: 0,
  revenueGrowth: 0
})
const loadMetrics = async () => {
  loading.value = true
  
  // 模拟 API 请求
  await new Promise(resolve => setTimeout(resolve, 1000))
  
  // 模拟数据
  metrics.totalOrders = Math.floor(Math.random() * 10000) + 5000
  metrics.totalRevenue = Math.floor(Math.random() * 1000000) + 500000
  metrics.avgOrderValue = metrics.totalRevenue / metrics.totalOrders
  metrics.conversionRate = Math.random() * 5 + 2
  metrics.newCustomers = Math.floor(Math.random() * 1000) + 200
  metrics.refundRate = Math.random() * 3 + 1
  metrics.repeatPurchaseRate = Math.random() * 30 + 20
  metrics.ordersGrowth = Math.random() * 20 - 5
  metrics.revenueGrowth = Math.random() * 25 - 5
  
  loading.value = false
}
const handleDateChange = (dates) => {
  console.log('日期范围变更:', dates)
  loadMetrics()
}
onMounted(() => {
  // 设置默认日期范围(最近30天)
  const end = new Date()
  const start = new Date()
  start.setDate(start.getDate() - 30)
  dateRange.value = [start, end]
  
  loadMetrics()
})
</script>
<style scoped>
.sales-dashboard {
  padding: 20px;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.header h3 {
  margin: 0;
  color: #303133;
}
.metric-card {
  height: 120px;
  display: flex;
  align-items: center;
}
.metric-title {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #606266;
  font-size: 14px;
}
.metric-title .el-icon {
  font-size: 16px;
  color: #409eff;
}
.currency {
  color: #67c23a;
  font-weight: bold;
}
:deep(.el-statistic__content) {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}
:deep(.el-statistic__head) {
  margin-bottom: 8px;
}
</style>API 文档 
Statistic Attributes 
| 属性名 | 说明 | 类型 | 默认值 | 
|---|---|---|---|
| value | 数值内容 | number | 0 | 
| decimal-separator | 设置小数点 | string | . | 
| formatter | 自定义数值展示 | function | — | 
| group-separator | 设置千分位标识符 | string | , | 
| precision | 数值精度 | number | 0 | 
| prefix | 设置数值的前缀 | string | — | 
| suffix | 设置数值的后缀 | string | — | 
| title | 数值的标题 | string | — | 
| value-style | 设置数值的样式 | object | — | 
| loading | 数值是否加载中 | boolean | false | 
Statistic Slots 
| 插槽名 | 说明 | 
|---|---|
| title | 标题内容 | 
| prefix | 数值前缀 | 
| suffix | 数值后缀 | 
| formatter | 数值内容 | 
最佳实践 
设计原则 
- 数据突出:统计数值应该是页面的视觉焦点
- 信息层次:合理使用标题、数值、前后缀建立信息层次
- 一致性:同一页面的统计组件应保持样式一致
数值格式化 
- 精度控制:根据数据类型选择合适的小数位数
- 千分位分隔:大数值使用千分位分隔提高可读性
- 单位标识:明确标注数值单位,避免歧义
用户体验 
- 加载状态:数据加载时显示骨架屏或加载动画
- 趋势指示:通过颜色和图标显示数据趋势
- 交互反馈:提供数据刷新和时间范围选择功能
响应式设计 
- 移动端适配:在小屏幕上调整字体大小和布局
- 弹性布局:使用栅格系统确保不同屏幕下的表现
- 内容优先:在空间有限时优先显示重要指标
常见问题 
数值不显示 
问题:设置了 value 但数值不显示
解决方案:
- 检查 value是否为有效数字
- 确认是否有自定义 formatter返回了空值
- 检查 CSS 样式是否影响显示
vue
<!-- 错误示例 -->
<el-statistic :value="undefined" />
<el-statistic :value="'abc'" />
<!-- 正确示例 -->
<el-statistic :value="0" />
<el-statistic :value="123.45" />格式化函数不生效 
问题:设置了 formatter 但格式化不生效
解决方案:确保 formatter 函数返回字符串或数字
vue
<!-- 错误示例 -->
<el-statistic 
  :value="1234" 
  :formatter="(value) => { console.log(value) }"
/>
<!-- 正确示例 -->
<el-statistic 
  :value="1234" 
  :formatter="(value) => value.toLocaleString()"
/>精度设置无效 
问题:设置了 precision 但小数位数不正确
解决方案:
- 确保 precision为非负整数
- 检查是否同时使用了 formatter(formatter 优先级更高)
vue
<!-- precision 会被 formatter 覆盖 -->
<el-statistic 
  :value="123.456" 
  :precision="2"
  :formatter="(value) => Math.floor(value)"
/>
<!-- 正确使用 precision -->
<el-statistic 
  :value="123.456" 
  :precision="2"
/>样式自定义问题 
问题:无法修改统计组件的样式
解决方案:使用 value-style 属性或深度选择器
vue
<template>
  <!-- 使用 value-style -->
  <el-statistic 
    :value="123" 
    :value-style="{ color: '#f56c6c', fontSize: '24px' }"
  />
  
  <!-- 使用 CSS 深度选择器 -->
  <el-statistic :value="123" class="custom-statistic" />
</template>
<style scoped>
.custom-statistic :deep(.el-statistic__content) {
  color: #67c23a;
  font-size: 28px;
  font-weight: bold;
}
</style>总结 
Statistic 统计组件是展示关键数据指标的重要工具,能够有效突出重要数值信息。通过本文档的学习,你应该能够:
- 理解统计组件的设计理念和使用场景
- 掌握基础用法和数值格式化
- 实现自定义前缀、后缀和样式
- 合理使用加载状态和交互功能
- 在实际项目中构建专业的数据展示界面
在实际开发中,建议根据业务需求选择合适的数值格式和展示样式,注意数据的准确性和实时性,确保统计组件能够真正帮助用户理解和分析数据。