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 相关文章推荐
XML+XSL 与 HTML 两种方案的结合
Apr 22 Javascript
对xmlHttp对象的理解
Jan 17 Javascript
简单常用的幻灯片播放实现代码
Sep 25 Javascript
JS将表单导出成EXCEL的实例代码
Nov 11 Javascript
jQuery validate插件实现ajax验证重复的2种方法
Jan 22 Javascript
javascript结合Flexbox简单实现滑动拼图游戏
Feb 18 Javascript
Listloading.js移动端上拉下拉刷新组件
Aug 04 Javascript
JavaScript省市区三级联动菜单效果
Sep 21 Javascript
Bootstrap组合上、下拉框简单实现代码
Mar 06 Javascript
Vue 中如何正确引入第三方模块的方法步骤
May 05 Javascript
深入了解query和params的使用区别
Jun 24 Javascript
vue+vant使用图片预览功能ImagePreview的问题解决
Apr 10 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
DC这些乐高系列动画电影你看过几部?
2020/04/09 欧美动漫
PHP 类商品秒杀计时实现代码
2010/05/05 PHP
shopex中集成的站长统计功能的代码简单分析
2011/08/11 PHP
php获取URL中带#号等特殊符号参数的解决方法
2014/09/02 PHP
PHP常用技术文之文件操作和目录操作总结
2014/09/27 PHP
Django中的cookie与session操作实例代码
2017/08/17 PHP
php基于Redis消息队列实现的消息推送的方法
2018/11/28 PHP
PHP序列化和反序列化深度剖析实例讲解
2020/12/29 PHP
在jQuery中 常用的选择器介绍
2013/04/16 Javascript
Javascript 绘制 sin 曲线过程附图
2014/08/21 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
2015/10/16 Javascript
bootstrap3 兼容IE8浏览器!
2016/05/02 Javascript
jQuery 获取跨域XML(RSS)数据的相关总结分析
2016/05/18 Javascript
全面解析JavaScript里的循环方法之forEach,for-in,for-of
2020/04/20 Javascript
Node.js如何自动审核团队的代码
2016/07/20 Javascript
Vue.js每天必学之表单控件绑定
2016/09/05 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
防止页面url缓存中ajax中post请求的处理方法
2017/10/10 Javascript
详解如何使用webpack打包JS
2018/06/21 Javascript
Bootstrap Table实现定时刷新数据的方法
2018/08/13 Javascript
详解vue-cli 3.0 build包太大导致首屏过长的解决方案
2018/11/10 Javascript
Python面向对象特殊成员
2017/04/24 Python
python正则表达式爬取猫眼电影top100
2018/02/24 Python
python下载微信公众号相关文章
2019/02/26 Python
python2和python3在处理字符串上的区别详解
2019/05/29 Python
Python循环中else,break和continue的用法实例详解
2019/07/11 Python
TensorFLow 变量命名空间实例
2020/02/11 Python
Python库skimage绘制二值图像代码实例
2020/04/10 Python
Smallable意大利家庭概念店:设计师童装及家居装饰
2018/01/08 全球购物
火山咖啡:Volcanica Coffee
2019/10/29 全球购物
文秘大学生求职信
2014/02/25 职场文书
机械工程师岗位职责
2014/06/16 职场文书
2014年语文教学工作总结
2014/12/17 职场文书
2015年计算机教师工作总结
2015/07/22 职场文书
python 多态 协议 鸭子类型详解
2021/11/27 Python
Apache Hudi数据布局黑科技降低一半查询时间
2022/03/31 Servers