- UI组件
- 前端
【免费下载链接】shadcn-vue
Vue port of shadcn-ui
本文围绕 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相关子组件(ChartLegend、ChartCrosshair等,见 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
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
data | Record<string, any>[] | 是 | — | 源数据,每一项是一个字典对象 |
categories | string[] | 是 | — | 从数据中挑选出的分类字段,用于填充图例与 Tooltip |
index | string | 是 | — | 设置映射到坐标轴的键(X 轴分类键) |
colors | string[] | 否 | — | 自定义图表颜色,默认由defaultColors按分类数量生成 |
margin | Spacing | 否 | { top: 0, bottom: 0, left: 0, right: 0 } | 容器四周的边距 |
filterOpacity | number | 否 | 0.2 | 非选中(图例中置灰)字段的透明度 |
xFormatter | (tick: number \| Date, i: number, ticks: number[] \| Date[]) => string | 否 | — | 格式化 X 轴标签的函数 |
yFormatter | (tick: number \| Date, i: number, ticks: number[] \| Date[]) => string | 否 | — | 格式化 Y 轴标签的函数 |
showXAxis | boolean | 否 | true | 控制 X 轴显隐 |
showYAxis | boolean | 否 | true | 控制 Y 轴显隐 |
showTooltip | boolean | 否 | true | 控制 Tooltip 显隐 |
showLegend | boolean | 否 | true | 控制图例显隐 |
showGridLine | boolean | 否 | true | 控制网格线显隐 |
customTooltip | Component | 否 | — | 传入自定义 Tooltip 组件 |
curveType | CurveType | 否 | CurveType.MonotoneX | 曲线类型(来自@unovis/ts) |
showGradient | boolean | 否 | true | 控制面积渐变填充的显隐 |
从源码实现看,所有带默认值的 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仅在showTooltip为true时生效,源码中ChartCrosshair只有在showTooltip为真时才渲染,并把custom-tooltip透传给它(见 AreaChart.vue)。
七、源码实现剖析
理解 AreaChart.vue 的实现有助于判断各 Props 的真实行为:
- 图层结构:根容器下依次是
ChartLegend(图例,受showLegend控制)、VisXYContainer(Unovis 坐标系容器),内部通过v-for按categories分别渲染一组VisArea(面积)+VisLine(描边折线)图层; - 渐变填充:组件使用
useId()生成唯一 ID(chartRef),在<defs>中为每个颜色定义linearGradient。当showGradient为true时,渐变从stop-opacity 0.4(5%)过渡到0(95%);关闭时则用纯色stop(见 AreaChart.vue); - 图例联动置灰:面积与折线的透明度都读取
legendItems中对应项的inactive状态,被置灰的分类透明度降为filterOpacity(默认0.2),这是filterOpacity参数的真实作用点(AreaChart.vue 与 L109); - 坐标轴:X 轴默认
grid-line=false且tick-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"的直接原因。
八、注意事项与局限
- Legacy 状态:Charts 模块整体标注为 Legacy,官方计划将其迁移到独立扩展仓库并适配 Tailwind v4,当前仓库内实现对应 Tailwind v3 时代;
- 版本要求:必须使用 Vue > 3.3(泛型 SFC 与
useId依赖); - 前置样式不可省略:未配置
--vis-tooltip-*与--vis-primary-color等变量会导致 Tooltip 样式异常或颜色缺失; - 随机数据示例:官方 Demo 使用
Math.random()生成演示数据,实际使用时应替换为稳定、真实的数据源,避免每次渲染数值跳变; - 尺寸控制:组件默认高度
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
相关推荐
ToolJet 表格组件服务端分页实战指南:基于 limit/offset 实现大数据量表格的高性能加载
ToolJet 表格组件服务端分页实战指南:基于 limit/offset 实现大数据量表格的高性能加载 导读 当表格数据量达到数万甚至数十万行时,把全部数据一
UI组件前端p5.js WebGL 模式架构深度解析:RendererGL、Shader、Texture 与 Geometry 四大核心对象
p5.js WebGL 模式架构深度解析:RendererGL、Shader、Texture 与 Geometry 四大核心对象 本文面向 p5.js 的贡献者
UI组件前端shadcn-vue 组件注册表 FAQ 实战指南:复杂组件结构、自定义 Tailwind 颜色与动画配置
shadcn vue 组件注册表 FAQ 实战指南:复杂组件结构、自定义 Tailwind 颜色与动画配置 组件注册表(registry)是 shadcn vu
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考