兼容d3.js的类矩阵网格及行过渡动画实现问题
问题概述
我设计了一个3列多行的网格,行结构类似文件夹层级(父项可包含子项,子项还能嵌套),最终要实现点击父项展开/收起子项的折叠效果。目前遇到两个核心问题:
- 添加行时是瞬间出现,无法实现缓入动画
- 尝试了
display: contents和subgrid两种布局,subgrid作为构建类矩阵结构的标准方案,却无法强制第二列宽度统一
解决方案
1. 实现添加行的缓入动画
display: contents的元素不生成盒模型,无法直接应用过渡动画。调整结构让每行作为独立网格项,通过CSS过渡控制透明度和高度:
- 给
.row设置基础过渡样式,初始隐藏新行 - 使用D3的
transition()方法在新行插入后触发动画
2. 统一subgrid列宽
subgrid的核心是子网格继承父网格的列定义,之前的错误在于子网格自行定义列模板。正确配置:
- 父容器定义统一的列尺寸
- 子行使用
grid-template-columns: subgrid完全继承父列宽,确保所有行的对应列宽度一致
修改后的完整代码
JavaScript
function update(data) { const rows = d3.selectAll('.grid_container') .selectAll('.row') .data(data, (d) => d.id) .join( enter => enter.append('div') .classed('row', true) .style('opacity', 0) .style('height', 0) .call(enter => enter.each(function(d) { d3.select(this) .selectAll('div') .data(d.content) .join('div') .text(d => d); })) .transition().duration(300) .style('opacity', 1) .style('height', 'auto'), update => update, exit => exit.transition().duration(300) .style('opacity', 0) .style('height', 0) .remove() ); } function genRow(i) { return { id: i, content: [...Array(3)].map((_, j) => i === 0 && j === 1 ? 'Super Long Line' : `Cell ${i + 1}/${j + 1}`) } } function addRow() { data.push(genRow(data.length)); update(data); } const data = [...Array(2)].map((_, i) => genRow(i)); update(data);
CSS
/* 统一基础网格样式 */ .grid_container { display: grid; grid-template-columns: 110px max-content auto; gap: 5px; margin-bottom: 20px; } /* 行样式:使用subgrid继承父列宽 */ .row { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; transition: all 0.3s ease; overflow: hidden; } .row > div { padding: 10px; } .row:nth-child(odd) > div { background-color: forestgreen; } .row:nth-child(even) > div { background-color: purple; } button { margin-bottom: 10px; padding: 8px 16px; }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script> <button onclick="addRow()">Add Row</button> <h1><code>subgrid 统一列宽 + 动画版</code></h1> <div id="contents" class="grid_container"> </div>
内容的提问来源于stack exchange,提问作者thothal
相关产品推荐
相关产品推荐

