>我有以下HTML结构来表示日历:
<table>
<thead>...</thead>
<tbody>
<tr>...</tr>
<tr>
<td day="4">...</td>
<td day="5">...</td>
<td day="6" class="is-startrange">...</td>
<td day="7">...</td>
<td day="8">...</td>
</tr>
<tr>
<td day="9">...</td>
<td day="10">...</td>
<td day="11">...</td>
<td day="12">
<button class="day" type="button">12</button>
</td>
<td day="13">...</td>
</tr>
</tbody>
</table>
我的问题是:从第 12 天的按钮开始,如何向上遍历,选择所有按钮元素,直到遇到is-startrange
类?每个表单元格都是一个表示日期的按钮,侦听器已添加到所有按钮元素中。单击日期时,我将获得所选日期作为起点。
我想为开始日期和选定日期之间的所有按钮元素添加样式(添加类或通过纯 CSS(。
有没有办法在 D3 选择或纯 CSS 中实现这一点?
正如Gerardo Furtado在他的评论中已经提到的,这个问题实际上不是关于向上遍历DOM,而是关于td
元素的迭代。这可以通过使用d3.selectAll("td")
轻松完成,这将产生页面上找到的所有td
的扁平选择。根据您的布局,您可能需要进一步将选择范围缩小到特定的表格,这可以通过将选择器调整为"table.myTable td"
、"#tableId td"
等来完成。
有了这个选择,你可以应用一个类,比如range
,通过使用selection.classed(names[, value])
,它可以接受传入的函数作为第二个参数value
:
如果值是一个函数,则为每个选定的元素计算该函数,按顺序传递当前基准 (d(、当前索引 (i( 和当前组(节点(,并将其作为当前 DOM 元素。然后,函数的返回值用于在每个元素上分配或取消分配类。
剩下的唯一任务是实现一个过滤器函数,该函数跟踪元素是否在所需或范围内,从而确定是否分配range
类。
以下代码片段显示了如何使用提供给.classed()
的过滤器函数rangeFilter()
将所有这些组合在一起:
// The day parameter determines the stop criterion
function rangeFilter(day) {
// This property is closed over by the following function to keep track of the
// range. If this is true, this element and following elements belong to the
// range until this property becomes false again once reaching the button's td.
var inRange = false;
// Filter function returning true, if the element belongs to the range.
return function(d) {
element = d3.select(this); // The actual td element of this iteration step.
// Evaluate if the element is still in the range or, in case the range has not
// yet started, check if we reached the td.is-startrange.
inRange = (inRange && element.attr("day") != day)
|| element.classed("is-startrange");
// XOR to exclude the .is-startrange element.
return inRange != element.classed("is-startrange");
}
}
d3.selectAll("button")
.on("click", function() {
// For all tds check if they belong to the range and set the class based
// on the result of the filter function passing in this buttons value.
d3.selectAll("td")
.classed("range", rangeFilter(d3.select(this).text()));
});
.is-startrange {
background-color: limegreen;
}
.range {
background-color: red;
}
<script src="https://d3js.org/d3.v4.js"></script>
<h1>Hit the button</h1>
<table>
<thead>...</thead>
<tbody>
<tr>...</tr>
<tr>
<td day="4">...4...</td>
<td day="5">...5...</td>
<td day="6" class="is-startrange">...6...</td>
<td day="7">...7...</td>
<td day="8">...8...</td>
</tr>
<tr>
<td day="9">...9...</td>
<td day="10">...10...</td>
<td day="11">...11...</td>
<td day="12">
<button class="day" type="button">12</button>
</td>
<td day="13">...13...</td>
</tr>
</tbody>
</table>