简介
SVG.js 是一个轻量级的 JavaScript 库,用于创建和操作 SVG 图形。本文介绍如何在 Vue3 项目中使用 SVG.js。
安装
npm install @svgdotjs/svg.js
基础使用
1. Vue 组件中初始化 SVG.js
<template>
<div ref="svgContainer"></div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { SVG } from "@svgdotjs/svg.js";
const svgContainer = ref(null);
onMounted(() => {
const draw = SVG().addTo(svgContainer.value).size(300, 300);
// 绘制一个红色矩形
draw.rect(100, 100).fill("#f06");
});
</script>
核心功能
1. 基本图形绘制
SVG.js 支持多种基本图形:
- 矩形
.rect(width, height)
- 圆形
.circle(radius)
- 椭圆
.ellipse(width, height)
- 直线
.line(x1, y1, x2, y2)
- 多边形
.polygon(points)
- 折线
.polyline(points)
2. 样式设置
// 设置填充和描边
draw.rect(100, 100)
.fill('#f06')
.stroke({ width: 2, color: '#333' })
.radius(10) // 圆角
### 3. 动画效果
SVG.js内置了强大的动画功能:
```javascript
// 简单动画
draw.rect(100, 100)
.animate(1000) // 1秒动画
.move(100, 50)
.rotate(45)
.fill('#0f9')
// 链式动画
draw.circle(50)
.animate(500).move(100, 100)
.animate(500).move(200, 100)
.animate(500).move(200, 200)
.animate(500).move(100, 200)
.loop() // 循环播放
4. 事件处理
const rect = draw.rect(100, 100).fill("#f06");
// 添加点击事件
rect.on("click", (event) => {
console.log("矩形被点击", event);
rect.fill("#0f9");
});
// 添加鼠标悬停事件
rect.on("mouseover", () => {
rect.animate().fill("#f90");
});
rect.on("mouseout", () => {
rect.animate().fill("#f06");
});
5. 组合与复用
// 创建可复用的符号
const symbol = draw.symbol();
symbol.rect(50, 50).fill("#f06");
symbol.circle(25).center(25, 25).fill("#fff");
// 使用符号
draw.use(symbol).move(10, 10);
draw.use(symbol).move(70, 10);
6. 与 Vue 响应式数据结合
<template>
<div ref="svgContainer"></div>
<input v-model.number="size" type="range" min="50" max="200" />
</template>
<script setup>
import { ref, watch, onMounted } from "vue";
import { SVG } from "@svgdotjs/svg.js";
const svgContainer = ref(null);
const size = ref(100);
const rect = ref(null);
onMounted(() => {
const draw = SVG().addTo(svgContainer.value).size(300, 300);
rect.value = draw.rect(size.value, size.value).fill("#f06");
});
watch(size, (newSize) => {
rect.value?.size(newSize, newSize);
});
</script>
高级主题
1. 性能优化
- 避免频繁重绘
- 使用
remember()
缓存元素 - 合理使用
group()
分组元素
2. 与 Vue 组件库集成
可以创建可复用的 SVG 组件:
<!-- SvgRect.vue -->
<template>
<div ref="svgContainer"></div>
</template>
<script setup>
import { ref, watch, onMounted } from "vue";
import { SVG } from "@svgdotjs/svg.js";
const props = defineProps({
width: { type: Number, default: 100 },
height: { type: Number, default: 100 },
color: { type: String, default: "#f06" },
});
const svgContainer = ref(null);
const rect = ref(null);
onMounted(() => {
const draw = SVG().addTo(svgContainer.value).size(300, 300);
rect.value = draw.rect(props.width, props.height).fill(props.color);
});
watch(
() => props.width,
(w) => rect.value?.width(w)
);
watch(
() => props.height,
(h) => rect.value?.height(h)
);
watch(
() => props.color,
(c) => rect.value?.fill(c)
);
</script>
常见问题
- SVG 元素不显示:检查容器尺寸和 SVG 初始化是否正确
- 动画不流畅:减少同时运行的动画数量
- 事件不触发:确保元素有足够的可见区域
扩展应用场景
1. 数据可视化
<template>
<div ref="svgContainer"></div>
</template>
<script setup>
import { ref, watch, onMounted } from "vue";
import { SVG } from "@svgdotjs/svg.js";
const props = defineProps({
data: { type: Array, required: true },
});
const svgContainer = ref(null);
let draw = null;
onMounted(() => {
draw = SVG().addTo(svgContainer.value).size(600, 400);
updateChart();
});
watch(() => props.data, updateChart, { deep: true });
function updateChart() {
draw?.clear();
// 绘制柱状图
const barWidth = 40;
const maxValue = Math.max(...props.data);
props.data.forEach((value, index) => {
const height = (value / maxValue) * 300;
draw
.rect(barWidth, height)
.move(index * (barWidth + 10), 400 - height)
.fill(`hsl(${index * 30}, 70%, 50%)`)
.on("mouseover", () => {
draw
.text(value.toString())
.move(index * (barWidth + 10), 380 - height)
.font({ size: 14 });
});
});
}
</script>
2. 交互式图形编辑器
<template>
<div ref="svgEditor"></div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { SVG } from "@svgdotjs/svg.js";
const svgEditor = ref(null);
let selectedShape = null;
onMounted(() => {
const draw = SVG().addTo(svgEditor.value).size(800, 600);
// 创建可拖动矩形
const rect = draw.rect(100, 100).move(50, 50).fill("#f06");
rect.draggable();
// 创建可拖动圆形
const circle = draw.circle(80).move(200, 100).fill("#09f");
circle.draggable();
// 选择形状
rect.on("click", () => selectShape(rect));
circle.on("click", () => selectShape(circle));
// 右键菜单
draw.on("contextmenu", (event) => {
event.preventDefault();
if (selectedShape) {
selectedShape.remove();
selectedShape = null;
}
});
});
function selectShape(shape) {
if (selectedShape) {
selectedShape.stroke({ width: 0 });
}
selectedShape = shape;
shape.stroke({ width: 2, color: "#000", dasharray: "5,5" });
}
</script>
3. SVG.js 插件集成
SVG.js 有许多强大的插件:
- svg.filter.js – 添加滤镜效果
import "@svgdotjs/svg.filter.js";
// 使用
rect.filterWith((add) => {
add.gaussianBlur(5);
});
- svg.draggable.js – 增强拖拽功能
import "@svgdotjs/svg.draggable.js";
// 使用
circle.draggable();
- svg.panzoom.js – 添加平移缩放功能
import "@svgdotjs/svg.panzoom.js";
// 使用
draw.panZoom();
4. 性能优化进阶
- 使用 SVG Symbol 减少 DOM 节点
const symbol = draw.symbol();
symbol.rect(50, 50).fill("#f06");
// 复用Symbol
for (let i = 0; i < 100; i++) {
draw.use(symbol).move(i * 60, 100);
}
- 批量操作减少重绘
// 不好的做法
for (let i = 0; i < 100; i++) {
draw.circle(10).move(i * 15, 100);
}
// 好的做法 - 使用group
const group = draw.group();
for (let i = 0; i < 100; i++) {
group.circle(10).move(i * 15, 100);
}
- 使用 requestAnimationFrame 优化动画
function animate() {
shape
.animate(16)
.move(x, y)
.after(() => {
x += dx;
y += dy;
requestAnimationFrame(animate);
});
}
animate();
高级调试技巧
1. 调试 SVG 元素
// 打印SVG元素的DOM节点
console.log(rect.node);
// 检查SVG元素的属性
console.log(rect.attr());
// 调试动画
rect.animate().during(function (pos) {
console.log("当前动画进度:", pos);
});
2. 性能分析
// 测量渲染性能
console.time("render");
draw.rect(100, 100).fill("#f06");
console.timeEnd("render"); // 输出渲染耗时
// 使用Chrome DevTools分析内存使用
window._svgElements = []; // 用于内存分析
for (let i = 0; i < 1000; i++) {
const el = draw.circle(10).move((i % 50) * 20, Math.floor(i / 50) * 20);
window._svgElements.push(el);
}
总结
SVG.js 与 Vue3 结合可以创建丰富的交互式图形应用。通过组件化封装,可以实现高度复用的 SVG 图形组件。
原文链接:https://code.ifrontend.net/archives/978,转载请注明出处。
评论0