本节书摘来异步社区《D3.js数据可视化实战手册》一书中的第2章,第2.5节,作者: 【加拿大】Nick Qi Zhu,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.5 使用子选择器
我们常常需要在特定范围下选择元素。例如,选取某个section元素下的所有div元素。本例中,我们将介绍D3中这种需求的不同的实现方式及各自的优缺点。
2.5.1 准备阶段
请在浏览器中打开如下文件的本地副本。
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter2/sub-selection.html
AI 代码解读
2.5.2 开始编程
下面的代码分别通过两种不同方式,选取了两个div元素。
<section id="section1">
<div>
<p>blue box</p>
</div>
</section>
<section id="section2">
<div>
<p>red box</p>
</div>
</section>
<script type="text/javascript">
d3.select("#section1 > div") // <-- A
.attr("class", "blue box");
d3.select("#section2") // <-- B
.select("div") // <-- C
.attr("class", "red box");
</script>
AI 代码解读
代码的视觉效果如图所示。
2.5.3 工作原理
尽管视觉效果相同,但是这个例子中使用了两种完全不同的子选择技术。我们在这里将分别讨论它们的优缺点,以及各自的使用场合。
3级选择器连接符:在行A中,d3.select方法接受了一个特别的字符串,这个字符串为用大于符号(U+003E, >)连接的两个元素名称。这种语法叫做连接符(这里大于号表示子连接符)。3级选择器支持一些不同的结构连接符。我们先来快速浏览一下一些常用连接符。
后代连接符:这个连接符的语法为selector selector。
后代连接符,顾名思义,用来描述两个选择器之间的广义父子关系。我们称之为广义,是因为第二个选择器可以是第一个选择器的任意后代。让我们来看一些例子。
<div>
<span>
The quick <em>red</em> fox jumps over the lazy brown dog
</span>
</div>```
使用以下选择器。
AI 代码解读
div em`
由于div是em元素的祖先,所以这个例子选取了其中的em元素。
子连接符:该连接符的语法为selector > selector。
子连接符描述了两个元素之间的严格父子关系。子连接符用一个大于号(U+003E,>)连接两个元素。
使用如下选择器。
span > em```
将选取出em元素,因为本例中em是span元素的一级子元素。而div>em将不会返回任何有效的选集,因为em并不是div的直接子元素。
提示.tif 3级选择器也支持相邻选择器,但由于用得比较少,我们先略过不讲。感兴趣的读者可以参考W3C 3级选择器文档``http://www.w3.org/TR/css3-selectors/#sibling-combinators``。
W3C 4级选择器还提供了许多有趣的连接符,如相邻后续(following-sibling)连接符或引用连接符,这些连接符同样非常强大。
D3子选择器:在行B和C中,我们使用了不同的子选择器技术。在本例中,行B通过“#section2”选取了一个section元素,然后在行C中级联选择了一个div元素。这种类似级联选择的方式构成了一个区域选择。从字面上来说,这意味着选择了一个嵌套在#secion2内部的div元素。而从语义上来说,这实质上类似于使用了后代连接符#section2 div。这种子选择方式的好处在于父元素是先被独立选取的,因此可以在继续选择子元素之前进行相应的处理,如以下代码所示。
AI 代码解读
d3.select("#section2") // <-- B
.style("font-size", "2em") // <-- B-1
.select("div") // <-- C
.attr("class", "red box");```
AI 代码解读
从以上代码可以看到,在选择div元素之前,我们在第B-1行中对#section2使用了一个修饰函数。我们在下一节中将进一步探索这种灵活性。