d3.js用selection.classed()修改类能否实现属性相对当前值生效?
问题原因
- CSS本身不支持
height: height*1.5这种直接引用元素当前属性值的表达式语法,浏览器无法识别这类写法,导致宽高样式完全失效。 - 若你操作的是SVG元素,
background-color属性对SVG元素无效,填充色需要用fill属性。 - 你调用
classed()方法时第二个参数传了字符串'true'/'false',JS中非空字符串会被转为布尔值true,导致移除类的逻辑实际没有生效。
解决方案1:CSS变量方案(无需手动存储还原值,推荐)
这个方案完全符合你只通过增删类实现效果的需求,改动很小:
- 首先修改D3动态设置元素尺寸的代码,把计算好的宽高同步存入元素的CSS自定义属性:
// 你原来给元素设置动态宽高的逻辑 d3.selectAll('.classToSelect') .attr('width', d => d.width) .attr('height', d => d.height) // 新增两行,把宽高存到CSS变量 .style('--orig-width', d => `${d.width}px`) .style('--orig-height', d => `${d.height}px`) // 如果是SVG元素可以同时存原始填充色 .style('--orig-fill', d => d.fill)
- 修正你的CSS类写法,用
calc()计算相对尺寸:
/* 普通HTML元素用这个 */ .isHovered { width: calc(var(--orig-width) * 1.5); height: calc(var(--orig-height) * 1.5); background-color: yellow; } /* SVG元素用这个 */ .isHovered { width: calc(var(--orig-width) * 1.5); height: calc(var(--orig-height) * 1.5); fill: yellow; }
- 修正你的事件代码,把
classed的第二个参数改为布尔值:
function handleMouseOver(d, i) { d3.selectAll('.classToSelect') .classed('isHovered', true); }; function handleMouseOut(d, i) { d3.selectAll('.classToSelect') .classed('isHovered', false); };
解决方案2:直接操作SVG属性(用到你提到的svgAnimatedWidth)
如果你不想用CSS方案,可以直接读取SVG元素的svgAnimatedWidth/svgAnimatedHeight属性拿到当前尺寸,不需要提前存储:
- 注意
svgAnimatedWidth返回的是SVGAnimatedLength对象,需要取.baseVal.value才能拿到数值型的尺寸值。 - 代码示例如下:
function handleMouseOver(event, d) { d3.selectAll('.classToSelect') .each(function() { // 把原始值存到元素的dataset里,移出时直接读取 this.dataset.origW = this.svgAnimatedWidth.baseVal.value; this.dataset.origH = this.svgAnimatedHeight.baseVal.value; this.dataset.origFill = this.getAttribute('fill'); }) .attr('width', function() { return this.dataset.origW * 1.5; }) .attr('height', function() { return this.dataset.origH * 1.5; }) .attr('fill', 'yellow'); }; function handleMouseOut(event, d) { d3.selectAll('.classToSelect') .attr('width', function() { return this.dataset.origW; }) .attr('height', function() { return this.dataset.origH; }) .attr('fill', function() { return this.dataset.origFill; }); };
如果你的元素宽高本来就是绑定到D3的数据上的,那甚至不需要存dataset,移出时直接从绑定的数据d里取原始值即可,逻辑更简单。
内容的提问来源于stack exchange,提问作者Benjamonster
相关产品推荐
相关产品推荐

