Appearance
Heatmap 热力图
用于展示一年(或任意区间)内每日的活跃度、提交量、访问量等按天聚合的指标。
何时使用
- 需要在一屏内看出一年中哪些天数值高、哪些天几乎为零。
- 数据天然按天聚合,且关注的是分布形态而不是精确数值比较。
- 常见于贡献图、打卡记录、可用性监控(如服务健康度日历)。
基础用法
默认按自然年渲染:year 指定年份,data 提供每天的数值。没有数据的天会使用 minimumColor。
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap :year="year" :data="data" :aria-label="`${year} 年活跃度`" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([
{ timestamp: new Date(year, 0, 3).getTime(), value: 12 },
{ timestamp: new Date(year, 0, 4).getTime(), value: 30 },
{ timestamp: new Date(year, 5, 18).getTime(), value: 5 },
{ timestamp: new Date(year, 8, 9).getTime(), value: 41 },
]);
</script>自定义范围
不传 year 时,可以用 startDate / endDate 指定任意区间;两者都不传时,会从 data 的首尾时间戳推导。
一三五
2025-092025-102025-112025-122026-012026-022026-032026-04
少多
vue
<template>
<x-heatmap :data="data" aria-label="跨年区间活跃度" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const data = ref([
{ timestamp: new Date(2026, 7, 1).getTime(), value: 8 },
{ timestamp: new Date(2026, 11, 20).getTime(), value: 26 },
{ timestamp: new Date(2027, 2, 14).getTime(), value: 31 },
]);
</script>自定义配色
activeColors 按由浅到深的顺序给出色阶,minimumColor 指定最小值(以及无数据格)的颜色。
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap
:year="year"
:data="data"
:active-colors="colors"
:minimum-color="minimumColor"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const minimumColor = ref('#ebedf0');
const colors = ref(['#9be9a8', '#40c463', '#30a14e', '#216e39', '#0e4429']);
const data = ref([
{ timestamp: new Date(year, 0, 3).getTime(), value: 1 },
{ timestamp: new Date(year, 3, 8).getTime(), value: 60 },
]);
</script>尺寸
size 支持 small / medium / large,影响格子边长与整体密度。
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap :year="year" :data="data" size="small" />
<x-heatmap :year="year" :data="data" size="medium" />
<x-heatmap :year="year" :data="data" size="large" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 4, 20).getTime(), value: 18 }]);
</script>标签与图例
showWeekLabels / showMonthLabels / showColorIndicator 可以分别关闭星期标签、月份标签与底部图例。firstDayOfWeek 控制一周从哪天开始。
二四六
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap :year="year" :data="data" :first-day-of-week="1" />
<x-heatmap
:year="year"
:data="data"
:show-week-labels="false"
:show-month-labels="false"
:show-color-indicator="false"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 2, 6).getTime(), value: 9 }]);
</script>点击事件与自定义提示
点击格子会派发 cell-click;tooltip 插槽可自定义悬浮内容。
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap :year="year" :data="data" @cell-click="handleCellClick" />
<p role="status">{{ selectedCell }}</p>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 6, 15).getTime(), value: 22 }]);
const selectedCell = ref('点击格子查看日期与值');
const handleCellClick = (cell: { date: string; value: number | null }) => {
selectedCell.value = `${cell.date} 的值为 ${cell.value ?? '空'}`;
};
</script>自定义 tooltip 内容:
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
<x-heatmap :year="year" :data="data">
<template #tooltip="{ date, value }">
自定义:{{ date }} / {{ value ?? '空' }}
</template>
</x-heatmap>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 8, 1).getTime(), value: 14 }]);
</script>加载状态
loading 为 true 时用 Spin 覆盖;也可以传对象透传给 Spin。
vue
<template>
<x-heatmap :year="year" :data="data" loading />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const year = new Date().getFullYear();
const data = ref([]);
</script>按需导入
ts
import { Heatmap } from 'x-next';样式按需引入(base.css 为共享基础层,多个组件只需引入一次):
ts
import 'x-next/style/base.css';
import 'x-next/style/heatmap.css';Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
data | 热力图数据 | HeatmapDataItem[] | [] |
year | 要渲染的自然年;优先于 startDate / endDate | number | - |
startDate | 自定义范围起始(时间戳或日期字符串) | number | string | - |
endDate | 自定义范围结束(时间戳或日期字符串) | number | string | - |
activeColors | 由浅到深的色阶 | string[] | 内置主色阶(5 档) |
minimumColor | 最小值与无数据格的颜色 | string | 跟随主题 |
size | 格子尺寸 | 'small' | 'medium' | 'large' | 'medium' |
firstDayOfWeek | 一周的起始日,0 为周日 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 |
showWeekLabels | 是否展示星期标签 | boolean | true |
showMonthLabels | 是否展示月份标签 | boolean | true |
showColorIndicator | 是否展示颜色图例 | boolean | true |
tooltip | 鼠标悬浮提示;传对象可配置内部浮层 | boolean | object | true |
loading | 加载中 | boolean | object | false |
ariaLabel | 无障碍名称:交互模式下作为网格的 aria-label,纯展示模式下让容器带 role="img" | string | 语言包默认文案 |
HeatmapDataItem
| 字段 | 说明 | 类型 |
|---|---|---|
timestamp | 该天的任意时间戳(内部按当天零点归并) | number |
value | 该天的值;null / 省略表示无数据 | number | null |
Events
| 事件名 | 说明 | 参数 |
|---|---|---|
cellClick | 点击某个日期格时触发 | (cell: HeatmapCell, ev: MouseEvent) |
HeatmapCell 包含 timestamp / date / value / level / rowIndex / colIndex。
Slots
| 插槽名 | 说明 | 参数 |
|---|---|---|
tooltip | 自定义悬浮提示内容 | HeatmapCell & { label: string } |
cell | 自定义格子内容 | HeatmapCell |
indicator | 自定义颜色图例 | { colors: string[] } |
indicator-leading-text | 图例左端文案 | - |
indicator-trailing-text | 图例右端文案 | - |
footer | 网格下方的补充内容 | - |
交互说明
- 色阶分档:有效值按
[min, max]均分到各档;全部数据同值时统一取最高档,避免整片落到最浅色。 - 性能:悬浮提示由整块网格共享一个节点(鼠标事件委托 + 按帧节流),不会为每个格子创建浮层实例;
tooltip关闭时改用原生title。 - 补齐格:为凑满整周,首尾会有日期属于区间之外的格子,它们带
x-heatmap-is-out-of-range类并降低不透明度。 - 月份标签:跨列数不足 3 周的月份不展示标签,以免相邻月份标注重叠。
- 键盘导航:网格可聚焦(
tooltip开启时)。左右方向键按天移动、上下方向键按周移动,Home / End 到当周首尾,Esc 关闭提示;移动时通过aria-live播报「日期:数值」,鼠标悬浮不播报。 - 无障碍结构:
tooltip开启时网格承担role="grid"(用aria-activedescendant指向当前格),避免role="img"把整块网格对读屏隐藏;关闭提示时容器带role="img"作为静态图像。