You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.js退出过渡动画失效:如何实现文本左移淡出效果?

问题根源分析

你的退出动画没触发的核心原因是D3无法识别新旧数据的差异,导致exit()集合始终是空的。具体来说:

  • 每次调用displayData时,你把单个数据包装成数组[data]传入,然后用.data([data])绑定数据,但没有指定key函数。D3默认用索引匹配数据,新旧数组都是长度1的数组,索引0的位置始终有数据,所以旧元素不会被标记为"需要退出"。
  • 另外,你在处理enter/update/exit的顺序上也没有配合动画逻辑设计,进一步导致动画无法触发。
修正方案(微调现有代码即可实现)

只需要两个关键改动就能解决问题:

  1. 给data()方法添加key函数,让D3通过Date字段区分不同的数据项
  2. 调整enter/update/exit的处理逻辑,确保退出动画能正确触发

下面是修正后的完整代码:

修正后的JS代码

var width = 200; 
var height = 100; 
var margins = {left:20, right:20, top:0, bottom:0 }; 
var svg = d3.select('body') 
  .append('svg') 
  .attr('width', width+margins.left+margins.right) 
  .attr('height', height+margins.top+margins.bottom); 

var data = [ 
  {'Date':'May-24', 'Event':'Event 1'}, 
  {'Date':'Jun-30', 'Event':'Event 2'} 
]; 

var dateG = svg.append('g') 
  .attr('transform', 'translate('+margins.left+','+(margins.top+40)+')') 
  .attr('class', 'uiText'); 

function displayData(newData) { 
  // 关键改动1:添加key函数,用Date字段作为数据项的唯一标识
  var dateText = dateG 
    .selectAll('text') 
    .data([newData], function(d) { return d.Date; }); 

  // 处理enter的新元素:设置初始不可见状态,再执行入场动画
  dateText.enter()
    .append('text')
    .attr('x', -50) // 初始在左侧不可见位置
    .attr('opacity', 0)
    .transition() // 新元素淡入+右移到目标位置
    .duration(750)
    .attr('x', 10)
    .attr('opacity', 1)
    .text(function(d) { return d.Date; });

  // 处理update的元素(此场景下不会触发,因为每次都是全新数据)
  dateText
    .text(function(d) { return d.Date; });

  // 关键改动2:正确触发exit元素的退出动画
  dateText.exit()
    .transition()
    .duration(750)
    .attr('x', -50)
    .attr('opacity', 0)
    .remove(); // 过渡结束后移除元素
} 

displayData(data[0]); 

d3.select('#button').on('click', function() { 
  displayData(data[1]); 
});

修正后的HTML代码(补全闭合标签+添加基础样式)

<!DOCTYPE html> 
<html lang="en"> 
<head> 
  <meta charset="utf-8"> 
  <script src="//d3js.org/d3.v3.min.js"></script> 
  <style>
    .button { cursor: pointer; padding: 8px; background: #eee; display: inline-block; margin: 10px; }
  </style>
</head>
<body>
  <div class='button' id='button'>Next Event</div>
</body>
</html>
改动细节解释
  1. key函数的作用:data([newData], function(d) { return d.Date; })告诉D3,每个数据项的唯一标识是Date字段。当你切换到Jun-30的数据时,D3会发现旧的May-24数据没有匹配项,就会把旧的text元素放入exit()集合,动画才有了执行对象。
  2. enter元素的入场动画:新增的text元素先放在左侧不可见位置,然后通过过渡动画移动到目标位置并淡入,和退出动画形成对称的视觉效果。
  3. exit元素的过渡逻辑:旧元素先左移并淡出,过渡完成后再被移除,这样就能看到完整的退出动画流程了。
额外说明

你之前尝试的delay()、单独调用remove()等操作无效,本质是因为exit()集合一直是空的,根本没有元素能执行这些过渡。只要解决了数据匹配的核心问题,退出动画就能正常触发。

内容的提问来源于stack exchange,提问作者Arash Howaida

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:03:16