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
在數據綁定、多層級數據上着實提供了極大的便利,此文能夠說是我的的學習總結,若有不足或錯誤之處還請大佬指出