选择器
选择单个元素(select)
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// @ts-ignore
const selection = select(myDivRef.value).select('p'); // 选择myDivRef这个dom元素之下的p, 由于使用的是select方法,因此实际只会返回匹配到的第一个p
selection.classed('colorRed', true) // 给选中的元素添加一个class: colorRed
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
选择所有匹配的元素(selectAll)
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p') // 选择myDivRef这个dom元素之下的所有p
selection.classed('colorRed', true) // 给选择的元素加上一个class: colorRed
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
数据设置
设置单个数据(datum)
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).select('p')
// 设置数据(数据源是单个数据)
selection.datum({ name: '张三', age: 21 })
// 设置匹配元素的显示内容,并给匹配元素添加一个class colorRed
selection
.text(
(dataItem: any, idx: number) =>
`数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
)
.classed('colorRed', true)
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
设置批量数据(data)
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是多个数据)
selection.data([
{ name: '张三', age: 21 },
{ name: '李四', age: 22 },
])
// 设置匹配元素的显示内容,并给匹配元素添加一个class colorRed
selection
.text(
(dataItem: any, idx: number) =>
`数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
)
.classed('colorRed', true)
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
数据与匹配元素的3种情况
数据数量与匹配元素数量一样
那么数据中的每一个会与元素中的每一个按照数据下标一一对应(如: 第一个数据元素, 对应第一个匹配的html元素)
此示例, 匹配的元素和数据都是两个
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是单个数据)
selection.data([
{ name: '张三', age: 21 },
{ name: '李四', age: 22 },
])
// 设置匹配元素的显示内容,并给匹配元素添加一个class colorRed
selection
.text((dataItem: any, idx: number) => {
console.log(dataItem)
return `数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
})
.classed('colorRed', true)
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
数据数量大于匹配元素数量
此示例, 数据两个, 匹配的元素一个
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是单个数据)
selection.data([
{ name: '张三', age: 21 },
{ name: '李四', age: 22 },
])
// 设置匹配元素的显示内容,并给匹配元素添加一个class colorRed
selection
.text((dataItem: any, idx: number) => {
console.log(dataItem)
return `数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
})
.classed('colorRed', true)
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
数据数量少于匹配元素数量
此示例数据为2, 匹配的元素为1, 此时会js会报错, 从结果可以推断出, selection.text(...)内部是按照匹配到的元素循环执行的, 并根据当前循环的数组下标从数据源的数组中获取数据, 如果没获取到数据, 那么text((dataItem)=>{...})中的dataItem将会是undefined
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是单个数据)
selection.data([{ name: '张三', age: 21 }])
// 设置匹配元素的显示内容,并给匹配元素添加一个class colorRed
selection
.text((dataItem: any, idx: number) => {
console.log(dataItem)
return `数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
})
.classed('colorRed', true)
console.log(selection)
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
Enter, Update, Exit
概念
如果数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。可以想象,会有两个数据没有元素与之对应,这时候 D3 会建立两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。如果数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。示意图如下所示。
获取update选集, enter选集,并进行相关操作
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是单个数据), 并返回 update选集
const updateSelection = selection.data([
{ name: '张三', age: 21 },
{ name: '李四', age: 22 },
{ name: '王武', age: 23 },
{ name: '赵六', age: 24 },
])
// 对 update选集 做更新操作
updateSelection
.text((dataItem: any, idx: number) => {
console.log('update', dataItem, idx)
return `数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
})
.classed('colorRed', true)
console.log(updateSelection)
// 获取 enter选集
const enterSelection = updateSelection.enter()
// 对enter选集做插入操作
enterSelection.append('p').text((dataItem: any, idx: number) => {
console.log('enter', dataItem, idx)
return `新人:${dataItem.name}, 年纪:${dataItem.age}, 索引号:${idx}`
})
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
从上图的结果中,可以得出以下结论
- 对update选集适合执行直接用数据对匹配的html元素进行更新
- 对enter选集适合先插入元素,再对插入的html元素进行更新
获取 exit选集, 并进行相应操作
<!--
@author: pan
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { selectAll, select } from 'd3-selection'
const myDivRef = ref<HTMLDivElement>()
onMounted(() => {
// 选择myDivRef下的第一个p
// @ts-ignore
const selection = select(myDivRef.value).selectAll('p')
// 设置数据(数据源是单个数据), 并返回update选集
const updateSelection = selection.data([
{ name: '张三', age: 21 },
{ name: '李四', age: 22 },
])
// 对update选集做更新操作
updateSelection
.text((dataItem: any, idx: number) => {
console.log('update', dataItem, idx)
return `数据索引号:${idx}, 姓名:${dataItem.name}, 年龄:${dataItem.age}`
})
.classed('colorRed', true)
console.log(updateSelection)
// // 获取enter选集
// const enterSelection = updateSelection.enter()
// enterSelection.append('p').text((dataItem: any, idx: number) => {
// console.log('enter', dataItem, idx)
// return `新人:${dataItem.name}, 年纪:${dataItem.age}, 索引号:${idx}`
// })
// 获取exit选集
const exitSelection = updateSelection.exit()
console.log('exitSelection', exitSelection)
// 如果先获取enter选集,再获取exit选集,那么会导致exit选集为空, 下面的text或remove代码就都无法执行
exitSelection.text((itemData: any, idx: number) => {
console.log('exit', itemData, idx)
return `exit: ${idx}`
})
// exitSelection.remove()
})
</script>
<template>
<p>我是第一个段落</p>
<div ref="myDivRef">
<p>我是div内部的第一个段落</p>
<p>我是div内部的第二个段落</p>
<p>我是div内部的第三个段落</p>
<p>我是div内部的第四个段落</p>
</div>
</template>
<style lang="scss" scoped>
.colorRed {
color: red;
}
</style>
从上面代码的测试结果中,可以得出以下结论
- 如果先获取enter选集,再获取exit选集,那么会导致exit选集为空, 下面的text或remove代码就都无法执行
- exit选集适合做remove操作