在上一篇文章中,我们梳理了 SVG 元素的“家族谱系”,知道了 SVGRectElement、SVGCircleElement 和 SVGEllipseElement 都共同继承自 SVGGeometryElement。换句话说,它们身上流淌着相同的“几何基因”——都拥有 getTotalLength()、getPointAtLength() 等几何计算能力。
但每个图形又有自己独特的“性格”:矩形有 width 和 height,圆形有 r(半径),椭圆则有 rx 和 ry(两个方向的半径)。理解这些异同,是你在 JavaScript 中精准操控它们的前提。
本文将从“声明 vs 操控” 的双重视角出发,带你逐一掌握这三种基础图形的接口用法,并最终通过一个综合交互 Demo,把理论知识转化为实战能力。
一、矩形:SVGRectElement
<rect> 是 SVG 中最基础的图形元素之一,用于绘制矩形——也可以带圆角。对应的 DOM 接口是 SVGRectElement。
1.1 核心属性一览
属性 | 对应标签属性 | 说明 |
|---|---|---|
x | x | 矩形左上角的 x 坐标 |
y | y | 矩形左上角的 y 坐标 |
width | width | 矩形的宽度 |
height | height | 矩形的高度 |
rx | rx | 圆角矩形在 x 方向的圆角半径 |
ry | ry | 圆角矩形在 y 方向的圆角半径 |
关键认知:这些属性都是只读的。这意味着你不能直接通过 rect.width = 200 来修改宽度。正确的修改方式是通过 setAttribute() 方法,或者操作 SVGAnimatedLength 对象的 baseVal 属性。
1.2 读取与修改的正确姿势
<svg viewBox="0 0 400 300">
<rect id="box" x="50" y="50" width="120" height="80" fill="blue" />
</svg>const rect = document.getElementById('box');
// 错误示范:直接赋值无效
// rect.width = 200; // 不会报错,但也不会生效
// 正确方式一:使用 setAttribute
rect.setAttribute('width', 200);
// 正确方式二:操作 baseVal(适用于需要读取精确值的场景)
console.log(rect.width.baseVal.value); // 120
rect.width.baseVal.value = 200; // 修改成功
// 读取当前值
console.log(rect.x.baseVal.value); // 50
console.log(rect.y.baseVal.value); // 50
console.log(rect.height.baseVal.value); // 801.3 圆角矩形的特殊处理
rx 和 ry 用于控制矩形的圆角。当只设置 rx 而不设置 ry 时,ry 默认等于 rx 的值。如果 rx 或 ry 的值超过矩形宽度或高度的一半,浏览器会自动将其限制为有效值。
const rect = document.getElementById('box');
// 设置圆角
rect.setAttribute('rx', 20);
rect.setAttribute('ry', 20);
// 读取圆角半径
console.log(rect.rx.baseVal.value); // 20
console.log(rect.ry.baseVal.value); // 20重要提示:rx 和 ry 除了作为 SVG 属性外,也可以作为 CSS 属性 使用。但要注意,CSS 属性优先级高于 SVG 属性,如果两者同时存在,CSS 值会覆盖 SVG 属性值。
二、圆形:SVGCircleElement
<circle> 元素用于基于圆心和半径绘制圆形。对应的 DOM 接口是 SVGCircleElement。
2.1 核心属性一览
SVGCircleElement 的实例属性同样全部是只读的 SVGAnimatedLength 类型:
属性 | 对应标签属性 | 说明 |
|---|---|---|
cx | cx | 圆心的 x 坐标(默认为 0) |
cy | cy | 圆心的 y 坐标(默认为 0) |
r | r | 圆的半径 |
2.2 操作示范
<svg viewBox="0 0 400 300">
<circle id="dot" cx="200" cy="150" r="60" fill="gold" />
</svg>const circle = document.getElementById('dot');
// 读取圆心坐标和半径
console.log(circle.cx.baseVal.value); // 200
console.log(circle.cy.baseVal.value); // 150
console.log(circle.r.baseVal.value); // 60
// 修改——通过 setAttribute
circle.setAttribute('r', 80);
circle.setAttribute('cx', 250);
// 修改——通过 baseVal
circle.r.baseVal.value = 100;2.3 一个常见陷阱
很多开发者会直觉地写出 circle.r = 100,然后发现没有任何变化。记住:SVGCircleElement 的属性都是只读的 SVGAnimatedLength 对象,不是普通的数字属性。正确的做法是使用 setAttribute 或操作 baseVal.value。
三、椭圆:SVGEllipseElement
<ellipse> 元素是圆形的“广义版本”——它在 x 和 y 两个方向上可以有不同的半径。对应的 DOM 接口是 SVGEllipseElement。
3.1 核心属性一览
SVGEllipseElement 的实例属性同样全部是只读的 SVGAnimatedLength 类型:
属性 | 对应标签属性 | 说明 |
|---|---|---|
cx | cx | 椭圆中心的 x 坐标 |
cy | cy | 椭圆中心的 y 坐标 |
rx | rx | 椭圆在 x 方向的半径(水平半径) |
ry | ry | 椭圆在 y 方向的半径(垂直半径) |
3.2 操作示范
<svg viewBox="0 0 400 300">
<ellipse id="oval" cx="200" cy="150" rx="120" ry="60" fill="coral" />
</svg>const ellipse = document.getElementById('oval');
// 读取
console.log(ellipse.cx.baseVal.value); // 200
console.log(ellipse.cy.baseVal.value); // 150
console.log(ellipse.rx.baseVal.value); // 120
console.log(ellipse.ry.baseVal.value); // 60
// 修改——通过 setAttribute
ellipse.setAttribute('rx', 150);
ellipse.setAttribute('ry', 80);
// 读取时还可以用 valueAsString 获取带单位的原始值
console.log(ellipse.rx.baseVal.valueAsString); // "150"实用技巧:valueAsString 可以获取属性值的原始字符串形式(包括单位,如 "150px" 或 "50%"),而 value 只返回纯数值。
四、它们共同的“超能力”:继承自 SVGGeometryElement
虽然三种图形的属性各不相同,但它们的接口都继承自 SVGGeometryElement。这意味着它们共享以下实用方法:
方法 | 说明 |
|---|---|
getTotalLength() | 返回图形轮廓的总长度 |
getPointAtLength(distance) | 返回轮廓上指定距离处的坐标点 |
isPointInFill(point) | 判断点是否在填充区域内 |
isPointInStroke(point) | 判断点是否在描边区域内 |
这些方法在实现路径动画、精确点击检测等高级交互时非常有用。我们将在后续文章中深入探讨。
五、综合实战:构建一个“图形控制面板”
理论讲完了,让我们把这些知识串联起来,构建一个可交互的图形控制面板——用户可以通过滑块实时调整图形的尺寸和位置。
5.1 HTML 结构
<svg viewBox="0 0 500 400" id="canvas">
<!-- 矩形 -->
<rect id="myRect" x="50" y="50" width="100" height="80" fill="#4A90D9" />
<!-- 圆形 -->
<circle id="myCircle" cx="250" cy="90" r="50" fill="#E67E22" />
<!-- 椭圆 -->
<ellipse id="myEllipse" cx="400" cy="90" rx="60" ry="40" fill="#27AE60" />
</svg><!-- 控制面板 -->
<div id="controls">
<h3>图形控制器</h3>
<div class="control-group">
<label>矩形宽度: <span id="rectWidthLabel">100</span></label>
<input type="range" id="rectWidth" min="20" max="200" value="100" />
</div>
<div class="control-group">
<label>矩形高度: <span id="rectHeightLabel">80</span></label>
<input type="range" id="rectHeight" min="20" max="150" value="80" />
</div>
<div class="control-group">
<label>圆形半径: <span id="circleRadiusLabel">50</span></label>
<input type="range" id="circleRadius" min="10" max="120" value="50" />
</div>
<div class="control-group">
<label>椭圆水平半径: <span id="ellipseRxLabel">60</span></label>
<input type="range" id="ellipseRx" min="20" max="150" value="60" />
</div>
<div class="control-group">
<label>椭圆垂直半径: <span id="ellipseRyLabel">40</span></label>
<input type="range" id="ellipseRy" min="20" max="120" value="40" />
</div>
</div>5.2 JavaScript 交互逻辑
// 获取图形元素
const rect = document.getElementById('myRect');
const circle = document.getElementById('myCircle');
const ellipse = document.getElementById('myEllipse');
const ellipseRx = document.getElementById('ellipseRx');
const ellipseRy = document.getElementById('ellipseRy');const rectWidthLabel = document.getElementById('rectWidthLabel');
const rectHeightLabel = document.getElementById('rectHeightLabel');
const circleRadiusLabel = document.getElementById('circleRadiusLabel');
const ellipseRxLabel = document.getElementById('ellipseRxLabel');
const ellipseRyLabel = document.getElementById('ellipseRyLabel');// 矩形宽度控制
rectWidth.addEventListener('input', () => {
const val = rectWidth.value;
rect.setAttribute('width', val);
rectWidthLabel.textContent = val;
});// 矩形高度控制
rectHeight.addEventListener('input', () => {
const val = rectHeight.value;
rect.setAttribute('height', val);
rectHeightLabel.textContent = val;
});// 圆形半径控制
circleRadius.addEventListener('input', () => {
const val = circleRadius.value;
circle.setAttribute('r', val);
circleRadiusLabel.textContent = val;
});// 椭圆水平半径控制
ellipseRx.addEventListener('input', () => {
const val = ellipseRx.value;
ellipse.setAttribute('rx', val);
ellipseRxLabel.textContent = val;
});// 椭圆垂直半径控制
ellipseRy.addEventListener('input', () => {
const val = ellipseRy.value;
ellipse.setAttribute('ry', val);
ellipseRyLabel.textContent = val;
});// 额外功能:点击图形时在控制台输出其当前属性
[rect, circle, ellipse].forEach(el => {
el.addEventListener('click', () => {
console.log(`点击了 ${el.tagName}`);
if (el.tagName === 'rect') {
console.log(` x: ${el.x.baseVal.value}, y: ${el.y.baseVal.value}`);
console.log(` width: ${el.width.baseVal.value}, height: ${el.height.baseVal.value}`);
} else if (el.tagName === 'circle') {
console.log(` cx: ${el.cx.baseVal.value}, cy: ${el.cy.baseVal.value}`);
console.log(` r: ${el.r.baseVal.value}`);
} else if (el.tagName === 'ellipse') {
console.log(` cx: ${el.cx.baseVal.value}, cy: ${el.cy.baseVal.value}`);
console.log(` rx: ${el.rx.baseVal.value}, ry: ${el.ry.baseVal.value}`);
}
});
});5.3 运行效果
打开页面后,你会看到三个不同颜色的图形并排排列。拖动下方的滑块,对应的图形会实时响应变化——矩形变宽变高、圆形放大缩小、椭圆在两个方向上分别拉伸。
点击任意图形,控制台会输出该图形的完整属性信息,这正是通过 baseVal.value 读取到的精确值。你可以直观地对比 setAttribute 和 baseVal 两种操作方式产生的效果。

六、常见错误与避坑指南
错误一:直接赋值属性
// 这样写不会生效!
rect.width = 200;
circle.r = 80;正确做法:使用 setAttribute() 或操作 baseVal.value。
错误二:忘记属性是 SVGAnimatedLength
// 你以为得到了数字,其实得到的是一个对象
const w = rect.width; // SVGAnimatedLength 对象,不是数字正确做法:通过 baseVal.value 获取数值。
错误三:混淆 CSS 属性和 SVG 属性
rx、ry、width、height 等属性既可作为 SVG 属性,也可作为 CSS 属性。当两者同时存在时,CSS 属性优先级更高。
/* CSS 中设置 */
rect {
width: 200px;
height: 150px;
}<!-- SVG 属性中设置 -->
<rect width="100" height="80" />此时,CSS 的 200px 和 150px 会覆盖 SVG 属性中的 100 和 80。如果遇到“改了属性但没变化”的情况,记得检查是否有 CSS 在“捣乱”。
七、本章总结
接口 | 对应元素 | 核心属性 | 独特性 |
|---|---|---|---|
SVGRectElement | <rect> | x,y,width,height,rx,ry | 支持圆角 |
SVGCircleElement | <circle> | cx,cy,r | 最简单的图形——只需圆心和半径 |
SVGEllipseElement | <ellipse> | cx,xy,rx,ry | 圆形的一般化——两个方向半径独立 |
三个核心要点
所有属性都是只读的 SVGAnimatedLength——修改时用 setAttribute 或操作 baseVal.value。
三者都继承自 SVGGeometryElement——共享 getTotalLength()、getPointAtLength() 等几何计算能力。
注意 CSS 与 SVG 属性的优先级——同名 CSS 属性会覆盖 SVG 属性。
下篇预告
在下一篇文章中,我们将迎来 SVG 中最强大、最复杂的图形元素——<path>(路径)。路径是 SVG 的“瑞士军刀”,几乎可以绘制任何形状。我们将深入探讨 SVGPathElement 接口,揭秘 d 属性的底层表示,并学习如何通过 JavaScript 动态拼接路径命令,绘制出属于你自己的贝塞尔曲线。
互动话题:动手运行文中的“图形控制面板”示例,试试把矩形和圆形的颜色也改成可调节的。你还可以为椭圆增加 cx 和 cy 的滑块,让它可以在画布上移动。欢迎在评论区分享你的扩展成果!