Vue 3 + Vite 中使用 F2 绘制移动端图表:从工程配置到自定义视图的完整指南
Vue 3 + Vite 中使用 F2 绘制移动端图表:从工程配置到自定义视图的完整指南
F2 是面向移动端的优雅、交互式、灵活的图表库。本文以仓库 packages/f2-vue/examples/vite 下的 Vue 3 + Vite 示例工程为主线,完整讲解如何在 Vue 3 项目中接入 F2:包括依赖安装、Vite 的 JSX 编译配置、用 <Canvas>/<Chart> 声明式组件搭建柱状图、编写自定义图形视图,以及通过 Vue 响应式数据驱动图表更新。读完本文,你可以在自己的 Vue 3 + Vite 工程中直接复刻这套可运行的图表方案。
该示例目录沿用了 Vue 3 + Vite 的标准模板结构(源码见 examples/vite),在其之上加入了 F2 图表的完整集成代码,是官方仓库中最直接的 Vue 集成样板。
示例工程目录结构
packages/f2-vue/examples/vite/
├── index.html # 页面入口,挂载 #app
├── package.json # 依赖与 npm 脚本
├── vite.config.js # Vite 插件与 JSX 编译配置
└── src/
├── App.vue # 根组件:声明式图表
├── graphic.jsx # 自定义视图组件(绘制年份文字)
└── main.js # Vue 应用入口
其中核心的图表渲染逻辑全部集中在 App.vue 的 <script lang='jsx'> 中,而 graphic.jsx 则演示了如何在图表坐标系内插入自定义绘制内容。
依赖清单与安装
参考 package.json,该示例工程的核心依赖如下:
| 依赖 | 版本 | 作用 |
|---|---|---|
@antv/f2 |
^5.0.0 |
移动端图表核心库,提供 Chart、Interval、Axis 等组件 |
@antv/f-engine |
1.x |
渲染引擎,同时也是 JSX 转换后的 importSource |
@antv/f-vue |
1.x |
F2 的 Vue 封装组件(即 <Canvas> 的出处) |
vue |
^3.2.25 |
Vue 3 运行时 |
开发依赖则用于解决 JSX 编译与 Vue 插件集成:
| 开发依赖 | 版本 |
|---|---|
@babel/plugin-transform-react-jsx |
^7.17.3 |
@rollup/plugin-babel |
^5.3.1 |
@vitejs/plugin-vue |
^2.3.2 |
@vitejs/plugin-vue-jsx |
^1.3.10 |
vite |
^2.9.7 |
npm 脚本与标准 Vite 工程一致:dev 启动开发服务器、build 产出构建结果、preview 预览构建产物。
注意:示例中直接写入了具体依赖版本号(Vite 为
^2.9.7、Vue 为^3.2.25),在实际新项目中可结合自身版本策略安装最新兼容版本,本示例的版本约束可作参考。
关键一步:配置 JSX 编译
F2 的声明式语法基于 JSX,因此 Vue 3 + Vite 下接入 F2 的第一道门槛是让 Vite 能正确编译图表中的 JSX 标签。示例的 vite.config.js 给出了完整答案:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { babel } from '@rollup/plugin-babel';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
babel({
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: '@antv/f-engine',
},
],
],
}),
vue(),
vueJsx(),
],
});
这里有三个要点需要理解:
@babel/plugin-transform-react-jsx负责转换图表 JSX:F2 图表语法中的<Canvas>、<Chart>、<group>、<text>等标签,本质上是渲染引擎的图元描述,必须被 Babel 插件转换为引擎调用。runtime: 'automatic'与importSource: '@antv/f-engine'决定 JSX 的运行时来源:自动运行时模式下,JSX 会被转换为从importSource指定模块导入的jsx函数调用,此处指定为渲染引擎@antv/f-engine,从而让图元标签正确落地到画布。作为对照,仓库官方文档 如何在 Vue 中使用 中展示的 Vite 配置同样采用这套写法,只是将importSource指向@antv/f2——两种写法分别对应图表标签与渲染引擎两种转换目标,需与你的依赖引入方式保持一致。vue()与vueJsx()负责常规 Vue 组件编译:App.vue内部使用render()+ JSX 的写法,需要@vitejs/plugin-vue-jsx支持。
如果你使用的是 vue-cli / webpack 工程,仓库文档也给出了等价方案:在 vue.config.js 中用 chainWebpack 为 .jsx 规则追加 Babel loader,并配置同样的 JSX 插件与 importSource(详见 site/docs/tutorial/framework/vue.zh.md)。
声明式绘制柱状图:App.vue 逐段解析
示例根组件 App.vue 完整演示了从数据到图表的声明式映射,核心代码骨架如下:
<script lang='jsx'>
import { toRaw } from 'vue';
import Canvas from '@antv/f-vue';
import { Chart, Interval, Axis } from '@antv/f2';
import Grahpic from './graphic';
const data1 = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
const data2 = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 20 },
{ genre: 'Shooter', sold: 50 },
{ genre: 'Other', sold: 50 },
];
export default {
name: 'App',
data() {
return {
year: '2021',
chartData: data1,
};
},
mounted() {
setTimeout(() => {
this.year = '2022';
this.chartData = data2;
}, 1000);
},
render() {
const { year, chartData } = this;
return (
<div className="container">
<Canvas pixelRatio={window.devicePixelRatio}>
<Chart data={toRaw(chartData)}>
<Grahpic year={year} />
<Axis field="genre" />
<Axis field="sold" />
<Interval x="genre" y="sold" color="genre" />
</Chart>
</Canvas>
</div>
);
},
};
</script>
<style>
.container {
width: 500px;
height: 300px;
}
</style>
几个值得注意的工程细节:
<script lang='jsx'>:该示例直接在.vue单文件组件中使用 JSX 语法,这是@vitejs/plugin-vue-jsx支持的用法。Canvas来自@antv/f-vue:<Canvas pixelRatio={window.devicePixelRatio}>是画布容器,通过pixelRatio适配移动端的高清屏(Retina/HiDPI 场景)显示精度。Chart、Axis、Interval来自@antv/f2:<Chart data={...}>接收数据源;<Axis field="genre" />、<Axis field="sold" />声明 x 轴与 y 轴;<Interval x="genre" y="sold" color="genre" />声明柱形几何体,并依据genre字段着色,形成按类目分组的多色柱状图。toRaw(chartData):这是 Vue 3 响应式系统与图表库衔接的关键。chartData是 Vue 的响应式数据(被 Proxy 包裹),直接传给图表库可能带来 Proxy 兼容性问题,用toRaw取出原始对象后再交给Chart,可以避免不必要的响应式开销与副作用。
样式方面,.container 通过固定宽高(500px × 300px)确定画布尺寸,这是 Canvas 类图表渲染的常见做法。
自定义视图组件:graphic.jsx
除了标准图表组件,F2 允许在坐标系内插入自定义绘制内容。示例的 graphic.jsx 演示了如何写一个自定义视图:
function View(props) {
const { coord, year } = props;
const { left, top, width, height } = coord;
const x = left + width / 2;
const y = top + height / 2;
return (
<group>
<text
attrs={{
x,
y,
text: year,
textAlign: 'center',
fontSize: '80px',
fill: '#ddd',
}}
/>
</group>
);
}
export default View;
其工作原理是:组件收到 coord(当前坐标系实例)与外部传入的 year 属性,从 coord 上解构出 left、top、width、height,从而计算出坐标系中心点 (x, y),然后在 <group> 下绘制一个居中的大号文字。在 App.vue 中它被当作普通子组件使用:<Grahpic year={year} />,让图表中央始终显示当前年份,起到类似“图内标注”的效果。
这一模式说明:F2 的 JSX 语法是完整的可组合渲染模型,<group>、<text> 等图元标签可以直接在自定义组件中使用,实现图表与业务定制内容的深度混合。
数据驱动更新:响应式让图表“活”起来
App.vue 的 mounted() 钩子里,组件挂载 1 秒后修改了 year 与 chartData:
mounted() {
setTimeout(() => {
this.year = '2022';
this.chartData = data2;
}, 1000);
}
由于 year、chartData 声明在 Vue 组件的 data() 中,变更会触发 render() 重新执行:图表中央年份从 2021 变为 2022,柱状图数据从 data1 切换到 data2(其中 Action 类目的销量从 120 变为 20、Shooter 从 350 变为 50,其余类目保持或变化,便于直观观察差异)。这验证了 F2 的 Vue 集成具备完整的响应式更新链路——只需修改 Vue 数据,图表即可自动重绘,无需手动调用任何更新 API。
工程入口:main.js 与 index.html
其余两个入口文件保持了标准 Vue 3 应用的形态:
- main.js:
createApp(App).mount('#app'),无特殊改动; - index.html:标准
#app挂载点,通过<script type="module" src="/src/main.js">加载模块入口,并配置了移动端viewport。
快速运行示例
在仓库根目录下,切换到示例目录安装依赖并启动:
cd packages/f2-vue/examples/vite
npm install
npm run dev # 启动 Vite 开发服务器
npm run build # 生产构建
npm run preview # 预览构建产物
开发模式下修改 App.vue 或 graphic.jsx 会触发热更新,可即时验证图表效果。
小结
通过 packages/f2-vue/examples/vite 这份示例,我们掌握了在 Vue 3 + Vite 中集成 F2 的完整链路:Babel 插件 + importSource 配置解决 JSX 编译 → <Canvas>/<Chart>/<Axis>/<Interval> 声明式拼装图表 → graphic.jsx 自定义视图扩展绘制 → toRaw 与 Vue 响应式数据协同实现图表热更新。这套模板同样适用于 Vue 3 + vue-cli(webpack)工程,只需将 JSX 编译配置迁移到 vue.config.js 的 chainWebpack 即可,具体参考 site/docs/tutorial/framework/vue.zh.md。如果你还想对比 webpack 体系的 Vue 3 示例,仓库中还有一份对应的 examples/vue3 工程可供参考。