d3中经过selection来操做元素,但selection并不能简单地被认为是“一个装了元素的数组”。本文学习自d3做者Mike Bostock的文章How Selections Work,同时添加了个人代码实践,代码均会放在CodePen
上给你们自行调试
但愿能起到理解selection的做用,不足或错误之处还请指出
javascript
那什么是selection呢?
selection并非一个DOM数组,它是数组的子类
与数组不一样点有以下:html
接下来的两个小标题将解释这两点java
selection提供了操做被选中DOM元素的方法,好比selection.attr、selection.style等等,同时也继承了数组的一些方法,好比array.forEach、array.map。固然,咱们通常不会使用这些原生方法,而是使用d3提供的更加方便的方法,好比selection.eachgit
selection是一个元素为group
的数组,每个group
是一个DOM数组
用图表能够这样表示,椭圆表示数组元素,中括号表示数组:
github
selection.selectAll可以得到有多个group的selection
。接下来咱们以
图表 + 代码 + 控制台打印
来讲明group,再说明group有什么做用
<h1></h1>
<h1></h1>
<h1></h1>
<h1></h1>
<script> const selection = d3.selectAll('h1'); <script> 复制代码
若是是数组
d3.select('h1')
复制代码
则会选择一个h1标签
bash
上文咱们提到过只有selection.selectAll可以得到有多个group的selectionapp
<h1>
<p></p>
<p></p>
</h1>
<h1>
<p></p>
<p></p>
</h1>
<script>
const h1Selection = d3.selectAll('h1');
const groupSelection = h1Selection.selectAll('p');
<script>
复制代码
父元素
,此例中则为h1
- 操做元素时,将相同层次结构的DOM元素以组划分,方便多组DOM元素的操做
- 数据绑定时,以group划分,方便多层次结构的数据绑定
group将相同层次结构的DOM元素以组划分,在进行多组DOM元素操做
时更加方便,所以,selction.attr与selection.style所调用函数的第二个参数是在group范围的下标,而不是selection范围的下标函数
groupSelection.attr('some-attr', (data, index)=>{
console.log('元素在group范围内的下标:' + index);
})
复制代码
至此,咱们能够看出selection并不能简单地认为是一个DOM元素数组,而是数组的子类,数组元素为group,同时提供了操做被选中DOM元素的方法
接下来咱们进一步探索selection的相关操做学习
只有selection.selectAll方法会生成含多个group的selection
由于select方法只会选中每一个group一个元素,因此select方法会保存已有的group
,同时传递已绑定的数据
const exampleData = [1, 2];
const h1Selection = d3.selectAll('h1');
const groupSelection = h1Selection.selectAll('p');
console.log(groupSelection);
groupSelection.data(exampleData)
const spanSelection = groupSelection.select('span');
console.log(spanSelection);
console.log(spanSelection.data());
复制代码
保存了原先存在的group,同时传递了数据
咱们把数据绑定在已有的div上,在div中插入p,就能够直接使用对应的数据进行操做了
那么数据绑定是“绑”到哪里的呢?d3把数据绑定到DOM元素的__data__属性上而非selection的属性上。
const data = [10,11,12];
const selection = d3.selectAll('div').data(data);
console.log(selection);
const DOMList = document.querySelectorAll('div');
console.log(DOMList);
复制代码
CodePen打开
咱们能够看到DOM元素中即有对应绑定的数据
<div></div>
<div></div>
<div></div>
<div></div>
......
const data = [10,11,12];
const selection = d3.selectAll('div').data(data);
......
console.log(d3.selectAll('div').data());
复制代码
selection.data是以group为单位进行数据绑定的,而不是以每个元素为单位
咱们来看看多个group的状况
以上图为例,当有多个group时,selection.data(argument1)传入的argument1为函数相比数组变量更为合适,同时这个函数的参数也会有对应的group下标
咱们仍是以代码为例更容易理解
<div>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
<!-- ...... -->
<!-- ......一共有三个相似的div组 -->
const dataArray = ['a', 'b', 'c', 'd'];
const groupSelection = d3.selectAll('div').selectAll('p');
console.log(groupSelection);
groupSelection.data((parentData, groupIndex)=>{
//console.log(parentData); //由于父元素无data绑定,因此返回undefined
console.log('groupIndex:' + groupIndex);
return dataArray;
});
console.log(groupSelection.data());
复制代码
CodePen打开
此处groupSelection.data()传入的为函数,此函数的第一个参数表示parentData,第二个参数就表示上文提到的groupIndex,由于有三个group,此例中会执行三次数据绑定,咱们也能够在控制台上看见按组划分的groupIndex
return dataArray
则对应绑定的数据
这里让咱们回想上文提到的group的另外一个做用:数据绑定时,以group划分,方便多层次结构的数据绑定
当我赶上多层次数据对应多组group的时候,咱们就能够减轻层级DOM及层级data的绑定
这里举一个简单的应用:
const hierarchicalData = [
['a', 'b', 'c', 'd'],
['e', 'f', 'g', 'h'],
['i', 'j', 'k', 'l']
];
.....
groupSelection.data((parentData, groupIndex)=>{
return hierarchicalData[groupIndex];
});
复制代码
这样,就能够把对应的多层次数据分别绑定到group之中
当当selection只有一个group时咱们传值就没必要传函数了,直接传数组便可,通常只有在多个group的状况下才须要向selection.data()传函数
当咱们把数据绑定到元素上时,是经过pairing keys(不知道咋翻译)匹配的,key是一个不可重复的字符串,用于为数据绑定进行匹配
最简单的key是取元素对应下标,这里我直接截取Mike Bostock文中内容
保持原有元素并绑定数据,而不是销毁重建
const oldData = [
{ name: "A", value: "I am A" },
{ name: "B", value: "I am B" },
{ name: "C", value: "I am C" },
{ name: "D", value: "I am D" },
{ name: "E", value: "I am E" },
];
const selection = d3.selectAll('div').data(oldData);
......
//模拟元素从新排序,此行代码后元素会倒序
const sortedSelection = selection.sort((a, b)=>{
return -1;
});
//新数据
const newData = [
{ name: "B", value: "I am B!!!!!" },
{ name: "A", value: "I am A!!!!!" },
{ name: "C", value: "I am C!!!!!" },
{ name: "D", value: "I am D!!!!!" },
{ name: "E", value: "I am E!!!!!" },
];
//匹配绑定
sortedSelection.data(newData, (d)=>{
return d.name;
});
复制代码
CodePen打开
咱们在绑定数据后对DOM元素进行重排,再次绑定新的数据时根据d.name匹配,能够发现元素顺序仍为重排后的顺序,而并未从新建立
在学习How Selections Work以后,我对selection及group有了更深的理解,group
、数据传递
及key parser
在数据绑定、多层级数据上着实提供了极大的便利,此文能够说是我的的学习总结,若有不足或错误之处还请大佬指出