shadcn-vue 面积图组件 AreaChart 使用指南:从 API 配置到自定义 Tooltip 实战
2026/9/24 13:48:46 网站建设 项目流程
  • UI组件
  • 前端

【免费下载链接】shadcn-vue

Vue port of shadcn-ui

项目地址:https://gitcode.com/gh_mirrors/sh/shadcn-vue
点击查看免费下载

本文围绕 shadcn-vue 仓库中图表体系(deprecated/www目录下基于 Unovis 构建的 Charts 模块)里的AreaChart面积图组件展开,完整梳理其全部 Props/Emit API、安装与 CSS 变量前置配置,并结合仓库内的 Demo 与源码实现,讲解基础面积图、Sparkline 迷你图、自定义 Tooltip 三类实战用法。读完本文,你将能够在自己的 Vue 3 项目中独立接入并深度定制 AreaChart,包括控制坐标轴、图例、渐变与曲线类型,以及注入自定义提示框组件。

一、AreaChart 是什么

AreaChart(面积图)通过在折线下方填充区域来展示数据随时间变化的趋势与模式,适合表达"总量走势""实际值与预测值对比"等场景。在 shadcn-vue 仓库中,它属于 Charts 图表模块 下的四种图表类型(Area / Line / Bar / Donut)之一,官方文档对它的定位是:

An area chart visually represents data over time, displaying trends and patterns through filled-in areas under a line graph.

需要说明的是,该组件处于Legacy / Alpha状态:官方文档明确标注 "Component will be moved to extended repo with Tailwind v4 support",且仅支持 Vue > 3.3。当前仓库中的实现位于 deprecated/www/src/registry/new-york/ui/chart-area/,底层构建于 Unovis(模块化数据可视化框架)之上,设计上参考了 Tremor。

组件对外暴露的 API 文档为自动生成的 AreaChart.md,它被@include到 面积图文档页 的 API 章节中;下方所有参数说明均与该文件及 源码类型定义 保持一致。

二、安装与前置配置

1. 添加组件

在项目根目录执行:

npx shadcn-vue@latest add chart-area

该命令会向项目注入chart-area组件(即 AreaChart.vue 及其导出),同时还需要随附的chart相关子组件(ChartLegendChartCrosshair等,见 chart 目录)。

2. 全局 CSS 变量配置

图表组件依赖 Unovis 的 CSS 变量来渲染 Tooltip 与坐标轴颜色。官方文档要求向tailwind.css@layer base中追加以下样式:

@layer base { :root { /* ... */ --vis-tooltip-background-color: none !important; --vis-tooltip-border-color: none !important; --vis-tooltip-text-color: none !important; --vis-tooltip-shadow-color: none !important; --vis-tooltip-backdrop-filter: none !important; --vis-tooltip-padding: none !important; --vis-primary-color: var(--primary); /* change to any hsl value you want */ --vis-secondary-color: 160 81% 40%; --vis-text-color: var(--muted-foreground); } }

要点:

  • --vis-tooltip-*系列变量统一置为none !important,是为了让 Unovis 原生 Tooltip 样式失效,从而使用 shadcn-vue 自绘的 ChartTooltip.vue / ChartCrosshair.vue;
  • --vis-primary-color建议映射到你的主题主色var(--primary)
  • --vis-secondary-color默认为示例中的绿色,可按需改成任意 hsl 值;
  • --vis-text-color用于坐标轴刻度文字颜色,源码中两个VisAxis均通过tick-text-color="hsl(var(--vis-text-color))"读取它(见 AreaChart.vue)。

如果你的组件没有使用 CSS 变量体系,则需要把--vis-primary-color--vis-text-color替换为你想要的固定 hsl 值,并且记得一并提供暗色模式下的取值。

三、API 完整参考(Props 与 Emits)

以下参数表完整继承了 AreaChart.md 的内容,并与 index.ts 中的BaseChartProps泛型定义逐一对应(T extends Record<string, any>表示数据项为字典对象)。

Props

名称类型必填默认值说明
dataRecord<string, any>[]源数据,每一项是一个字典对象
categoriesstring[]从数据中挑选出的分类字段,用于填充图例与 Tooltip
indexstring设置映射到坐标轴的键(X 轴分类键)
colorsstring[]自定义图表颜色,默认由defaultColors按分类数量生成
marginSpacing{ top: 0, bottom: 0, left: 0, right: 0 }容器四周的边距
filterOpacitynumber0.2非选中(图例中置灰)字段的透明度
xFormatter(tick: number \| Date, i: number, ticks: number[] \| Date[]) => string格式化 X 轴标签的函数
yFormatter(tick: number \| Date, i: number, ticks: number[] \| Date[]) => string格式化 Y 轴标签的函数
showXAxisbooleantrue控制 X 轴显隐
showYAxisbooleantrue控制 Y 轴显隐
showTooltipbooleantrue控制 Tooltip 显隐
showLegendbooleantrue控制图例显隐
showGridLinebooleantrue控制网格线显隐
customTooltipComponent传入自定义 Tooltip 组件
curveTypeCurveTypeCurveType.MonotoneX曲线类型(来自@unovis/ts
showGradientbooleantrue控制面积渐变填充的显隐

从源码实现看,所有带默认值的 Props 都由withDefaults集中声明(AreaChart.vue),其中margin使用工厂函数返回新对象以避免共享引用。

Emits

名称载荷类型说明
legendItemClick[d: BulletLegendItemInterface, i: number]点击图例某一项时触发,参数为图例项对象与索引

legendItemClick由内部的handleLegendItemClick转发(见 AreaChart.vue),可用于监听用户对图例项的交互(例如联动外部筛选器)。

四、基础用法:双分类面积图

以官方 AreaChartDemo.vue 为例,展示"实际值 total + 预测值 predicted"双曲线面积图:

<script setup lang="ts"> import { AreaChart } from "@/registry/new-york/ui/chart-area" const data = [ { name: "Jan", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Feb", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Mar", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Apr", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "May", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Jun", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Jul", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, ] </script> <template> <AreaChart :data="data" index="name" :categories="['total', 'predicted']" /> </template>

关键点:

  • index="name"把数据中的name字段映射为 X 轴分类键;
  • categories传入两个字段名,图例与 Tooltip 会按这两个分类渲染;
  • 不传colors时,源码通过defaultColors(props.categories.length)(见 AreaChart.vue)按分类数量生成默认配色。

也可以显式传colors覆盖默认色:

<template> <AreaChart :data="data" index="name" :categories="['total', 'predicted']" :colors="['blue', 'pink', 'orange', 'red']" /> </template>

五、Sparkline 迷你走势图

把面积图变成极简的 Sparkline,只需隐藏坐标轴、网格线与图例。官方 AreaChartSparkline.vue 给出了完整示例:

<script setup lang="ts"> import { CurveType } from "@unovis/ts" import { AreaChart } from "@/registry/new-york/ui/chart-area" const data = [ { name: "Jan", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Feb", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Mar", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Apr", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "May", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Jun", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Jul", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Aug", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Sep", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Oct", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Nov", total: Math.floor(Math.random() * 2000) + 1000 }, { name: "Dec", total: Math.floor(Math.random() * 2000) + 1000 }, ] </script> <template> <AreaChart class="h-[100px] w-[400px]" index="name" :data="data" :categories="['total']" :show-grid-line="false" :show-legend="false" :show-x-axis="false" :show-y-axis="false" :curve-type="CurveType.Linear" /> </template>

要点:

  • 通过:show-x-axis="false":show-y-axis="false":show-grid-line="false":show-legend="false"关闭所有辅助元素;
  • 组件根节点是w-full h-[400px]的容器,通过class覆盖为h-[100px] w-[400px]控制尺寸(源码在根节点使用cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')合并类名,见 AreaChart.vue);
  • CurveType.Linear换成直线曲线,视觉效果更"干脆"。

六、自定义 Tooltip

如果默认 Tooltip 不满足需求,可通过customTooltip传入一个自定义 Vue 组件。官方 AreaChartCustomTooltip.vue 示例:

<script setup lang="ts"> import { AreaChart } from "@/registry/new-york/ui/chart-area" import CustomChartTooltip from "./CustomChartTooltip.vue" const data = [ { name: "Jan", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Feb", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Mar", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Apr", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "May", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Jun", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, { name: "Jul", total: Math.floor(Math.random() * 2000) + 500, predicted: Math.floor(Math.random() * 2000) + 500 }, ] </script> <template> <AreaChart index="name" :data="data" :categories="['total', 'predicted']" :custom-tooltip="CustomChartTooltip" /> </template>

自定义组件接收固定的 Props 结构(见 CustomChartTooltip.vue):

defineProps<{ title?: string data: { name: string color: string value: any }[] }>()

其中data数组的每一项对应一个分类:name为分类名,color为该分类在图中的颜色,value为当前悬停点的数值。仓库自带的默认实现是 ChartTooltip.vue,你可以参考它来编写自己的样式,例如用Card组件把每项渲染成"色条 + 名称 + 数值"的布局:

<script setup lang="ts"> import { Card, CardContent } from "@/registry/new-york/ui/card" defineProps<{ title?: string data: { name: string color: string value: any }[] }>() </script> <template> <Card class="text-sm"> <CardContent class="p-3 min-w-[180px] flex flex-col gap-2"> <div v-for="(item, key) in data" :key="key" class="flex justify-between items-center"> <div class="flex items-center"> <span class="w-1 h-7 mr-4 rounded-full" :style="{ background: item.color }" /> <span>{{ item.name }}</span> </div> <span class="font-semibold ml-4">{{ item.value }}</span> </div> </CardContent> </Card> </template>

注意:customTooltip仅在showTooltiptrue时生效,源码中ChartCrosshair只有在showTooltip为真时才渲染,并把custom-tooltip透传给它(见 AreaChart.vue)。

七、源码实现剖析

理解 AreaChart.vue 的实现有助于判断各 Props 的真实行为:

  • 图层结构:根容器下依次是ChartLegend(图例,受showLegend控制)、VisXYContainer(Unovis 坐标系容器),内部通过v-forcategories分别渲染一组VisArea(面积)+VisLine(描边折线)图层;
  • 渐变填充:组件使用useId()生成唯一 ID(chartRef),在<defs>中为每个颜色定义linearGradient。当showGradienttrue时,渐变从stop-opacity 0.4(5%)过渡到0(95%);关闭时则用纯色stop(见 AreaChart.vue);
  • 图例联动置灰:面积与折线的透明度都读取legendItems中对应项的inactive状态,被置灰的分类透明度降为filterOpacity(默认0.2),这是filterOpacity参数的真实作用点(AreaChart.vue 与 L109);
  • 坐标轴:X 轴默认grid-line=falsetick-line=false,tick 文案默认由data[v]?.[index]取回原始分类名;Y 轴网格线由showGridLine控制,并给网格线附加了text-muted样式类;
  • 挂载时序:通过useMounted()延迟设置容器高度为100%,避免 SSR/首屏时 Unovis 容器高度计算异常;
  • 响应式类型:组件使用 Vue 3.3+ 的generic="T extends Record<string, any>"泛型语法,这也是文档强调"仅支持 Vue > 3.3"的直接原因。

八、注意事项与局限

  1. Legacy 状态:Charts 模块整体标注为 Legacy,官方计划将其迁移到独立扩展仓库并适配 Tailwind v4,当前仓库内实现对应 Tailwind v3 时代;
  2. 版本要求:必须使用 Vue > 3.3(泛型 SFC 与useId依赖);
  3. 前置样式不可省略:未配置--vis-tooltip-*--vis-primary-color等变量会导致 Tooltip 样式异常或颜色缺失;
  4. 随机数据示例:官方 Demo 使用Math.random()生成演示数据,实际使用时应替换为稳定、真实的数据源,避免每次渲染数值跳变;
  5. 尺寸控制:组件默认高度400px,通过class覆盖;如需精确控制图表绘制区域,可配合marginProp 调整容器边距。

九、相关参考文件

  • API 元数据(自动生成):AreaChart.md
  • 官方文档页:area.md、charts.md
  • 组件实现:AreaChart.vue、index.ts
  • 官方示例:AreaChartDemo.vue、AreaChartSparkline.vue、AreaChartCustomTooltip.vue、CustomChartTooltip.vue
  • 配套子组件:chart 目录
  • UI组件
  • 前端

【免费下载链接】shadcn-vue

Vue port of shadcn-ui

项目地址:https://gitcode.com/gh_mirrors/sh/shadcn-vue
点击查看免费下载

相关推荐

上一篇:Ktor应用逆向实战:android-reverse-engineering-skill如何抓出字符串路径与Auth插件
下一篇:Kubernetes AI控制台实战指南:企业级K8M深度解析与最佳实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询