D3.js中data(), enter() 和 exit()的问题详解


Posted in Javascript onAugust 17, 2015

D3的应用非常广泛,现在成为了主流数据可视化工具之一。大家在刚接触使用d3.js的时候,感到最吃力的地方是data(), enter(), exit()这几个操作。

在我接触一段时间,有了一些了解之后,简单说说我的理解。

data()

先看一个例子:

<body>
 <p></p>
 <p></p>
 <p></p>
</body>

执行代码:

d3.select("body").selectAll("p").data([1, 2, 3])

这里,data()是用来绑定数据到选择的DOM元素上.这样以后,就可以针对这些数据做一些相关操作,比如设置元素宽度等。

从表面上,并不能看出什么变化。但在内部,它是在对应的DOM元素上添加了一个__data__属性,可以通过document.getElementsByTagName("p")[0].__data__看到。

enter()和exit()

这两个操作令人困惑是因为单从名字上看,很难推断出它们的作用。

在上面data()的例子中,我们的DOM元素和数据的个数是一样的。但如果不一样的话,我们该怎么办?

enter()和exit()就是用来处理这种情况的。

enter()

当DOM数量少于data的数量,或者压根一个都没有的时候,我们一般会希望让程序帮忙创建。

下面的例子,我们没有事先提供DOM元素:

<body>
</body>

仍旧执行:

d3.select("body").selectAll("p").data([1, 2, 3])

与上面例子不同的是,上面的例子中我们可以继续执行.style("width", "100px")等操作。但这里我们不能了,因为我们没有选择到DOM元素,需要先创建。

enter()是用来在绑定数据之后,选择缺少的那部分DOM元素。我们可能会疑惑,既然是缺少的部分,怎么选择呢?这里就需要我们发挥一点想象力,想象我们选择了一些不存在的东西。我们可以称之为“虚拟DOM”或“占位符(placeholder)”。

enter()只是进行选择,并未实际添加所需DOM元素。因此在enter()之后一般都会配合append()来进行DOM元素的实际创建。

由此以来,我们使用 d3.select("body").selectAll("p").data([1, 2, 3]).enter().append("p") 即可根据数据自动创建所需的DOM元素。

enter的处理方法

如果没有足够的元素,那么处理方法通常是使用append()添加元素。请看下面的代码:

<body> 
  <p></p> 
  <script> 
  var dataset = [3, 6, 9]; 
  var p = d3.select("body").selectAll("p"); 
//绑定数据后,分别获取update和enter部分 
  var update = p.data(dataset); 
  var enter = update.enter();   
//update部分的处理方法是直接修改内容 
  update.text( function(d){ return d; } ); 
//enter部分的处理方法是添加元素后再修改内容 
  enter.append("p") 
   .text(function(d){ return d; }); 
  </script> 
 </body>

 本例中,body中的p元素只有一个,但是数据有三个,因此enter部分包含多余的两个数据。对多余数据的处理方法就是append元素,与之对应。经过处理后,body里有三个p元素,内容分别为:

<p>3</p> 
<p>6</p> 
<p>9</p>

通常,从服务器读取文件后,数据是有的,但是网页中是没有元素的。这是D3一个很重要的特性,即可以选择一个空集,然后使用enter().append()的形式来插入元素。假设现在body里没有p元素,请看如下代码:

var dataset = [10,20,30,40,50]; 
var body = d3.select("body"); 
body.selectAll("p") //选择body中所有p,但由于没有p,所以选择了一个空集 
 .data(dataset)  //绑定dataset数组 
 .enter()   //返回enter部分 
 .append("p")  //添加p元素 
 .text(function(d){ return d; });

上述代码中,selectAll选择了一个空集,然后绑定了数据。由于选择集为空,那么data()返回的update部分为空。然后调用enter()和append(),使得每一个数据都有元素p与之对应。最后再更改p元素的内容。即enter部分的常见处理方法是使用append()添加元素。

exit()

与enter()相反,exit()是用来选择那些与数据相比多出来的DOM元素。

在下面例子中,我们多提供了一个DOM元素:

<body>
 <p></p>
 <p></p>
 <p></p>
 <p></p>
</body>

这回就容易理解了,因为是多出来的,那么就是实际存在的,即最后一个<p>。

多出来的话,我们可以接着用.remove()移除这些元素,代码如下:

d3.select("body").selectAll("p").data([1, 2, 3]).exit().remove();

exit的处理方法

有多出的元素,没有数据与之对应。对于这样的元素,通常的做法是使用remove()删除元素。假设body中有5个p元素,请看如下代码:

var dataset = [10, 20, 30]; 
 var p = d3.select("body").selectAll("p"); 
//绑定数据之后,分别获取update部分和exit部分 
 var update = p.data(dataset); 
 var exit = update.exit(); 
//update的部分的处理方法是修改内容 
 update.text( function(d){ return d; } ); 
//exit部分的处理方法是删除 
 exit.remove();

这段代码中,对于exit部分的处理方法是删除。删除之后,网页中将不会有多余的p元素。

参考资料

"Thinking with Joins" - by Mike Bostock

Javascript 相关文章推荐
jquery仿京东导航/仿淘宝商城左侧分类导航下拉菜单效果
Apr 24 Javascript
JavaScript实现GriwView单列全选(自写代码)
May 13 Javascript
javascript实现div的显示和隐藏的小例子
Jun 25 Javascript
封装html的select标签的js操作实例
Jul 02 Javascript
jquery三个关闭弹出层的小示例
Nov 05 Javascript
node.js中的path.delimiter方法使用说明
Dec 09 Javascript
Hallo.js基于jQuery UI所见即所得的Web编辑器
Jan 26 Javascript
JavaScript简单获取系统当前时间完整示例
Aug 02 Javascript
js自定义QQ菜单效果
Jan 10 Javascript
JavaScript中join()、splice()、slice()和split()函数用法示例
Aug 24 Javascript
在Angular中使用JWT认证方法示例
Sep 10 Javascript
vue实现循环滚动列表
Jun 30 Javascript
关于js里的this关键字的理解
Aug 17 #Javascript
Nginx上传文件全部缓存解决方案
Aug 17 #Javascript
jQuery幻灯片带缩略图轮播效果代码分享
Aug 17 #Javascript
javascript中 try catch用法
Aug 16 #Javascript
javascript中undefined与null的区别
Aug 16 #Javascript
swtich/if...else的替代语句
Aug 16 #Javascript
javascript数组去重的六种方法汇总
Aug 16 #Javascript
You might like
javascript XMLHttpRequest对象全面剖析
2010/04/24 Javascript
JavaScript加强之自定义event事件
2013/09/21 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
javascript模拟地球旋转效果代码实例
2013/12/02 Javascript
JavaScript判断文件上传类型的方法
2014/09/02 Javascript
jQuery Ajax中的事件详细介绍
2015/04/16 Javascript
使用jquery实现的循环连续可停顿滚动实例
2016/11/23 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
图文详解Javascript中的上下文和作用域
2017/02/15 Javascript
原生js实现倒计时--2018
2017/02/21 Javascript
JavaScript比较两个数组的内容是否相同(推荐)
2017/05/02 Javascript
vue+webpack实现异步组件加载的方法
2018/02/03 Javascript
vue实现简单的日历效果
2020/09/24 Javascript
LayUI数据接口返回实体封装的例子
2019/09/12 Javascript
vue 清空input标签 中file的值操作
2020/07/21 Javascript
vant 自定义 van-dropdown-item的用法
2020/08/05 Javascript
JavaScript实现商品评价五星好评
2020/11/30 Javascript
Python的Flask框架中SQLAlchemy使用时的乱码问题解决
2015/11/07 Python
python 爬取微信文章
2016/01/30 Python
浅谈Python实现贪心算法与活动安排问题
2017/12/19 Python
Java实现的执行python脚本工具类示例【使用jython.jar】
2018/03/29 Python
深入理解python中sort()与sorted()的区别
2018/08/29 Python
Django如何将URL映射到视图
2019/07/29 Python
python PyQt5/Pyside2 按钮右击菜单实例代码
2019/08/17 Python
解决Django删除migrations文件夹中的文件后出现的异常问题
2019/08/31 Python
使用python绘制温度变化雷达图
2019/10/18 Python
Django 解决上传文件时,request.FILES为空的问题
2020/05/20 Python
CSS3 实现的火焰动画
2020/12/07 HTML / CSS
canvas之自定义头像功能实现代码示例
2017/09/29 HTML / CSS
trivago美国:全球最大的酒店价格比较网站
2018/01/18 全球购物
卡骆驰英国官网:Crocs英国
2019/08/22 全球购物
优秀女职工事迹材料
2014/02/06 职场文书
测绘工程专业求职信
2014/07/15 职场文书
《1942》观后感
2015/06/08 职场文书
Java 在生活中的 10 大应用
2021/11/02 Java/Android
JavaScript实现栈结构详细过程
2021/12/06 Javascript