我有以下日期选择器。问题是,当运行屏幕阅读器(NVDA)时,当使用 keyboard 将日期选择器网格上的选择移动到不同的单元格时,屏幕阅读器只会显示“空白”。 (但是,如果我用鼠标悬停在单元格上,它确实会正确读取当天的数字。)
$(document).ready(function () {
$('#ui-datepicker-div').addClass("month-calendar-widget");
$(".month-calendar input").datepicker({
showOtherMonths: true,
minDate: 0,
beforeShow: function () {
$('#ui-datepicker-div').addClass("month-calendar-widget");
}
}).datepicker("setDate", convertDateToUTC(new Date()));
});
我希望通过使用
aria-label
将 beforeShowDay
属性添加到网格的每个单元格来解决此问题,如下所示:
beforeShowDay: function(date) {
var dateString = $.datepicker.formatDate('MM d, yy', date);
return [true, '', dateString + "" + 'aria-label="' + dateString + '" role="gridcell" aria-selected="false"'];
}
但是,这会导致以下错误的 html:
<td class=" " data-event="click" data-handler="selectDay" data-month="1" data-year="2024" title="February 16, 2024aria-label="February 16, 2024" role="gridcell" aria-selected="false"">
<a class="ui-state-default" href="#">16</a>
</td>
我错过了什么?
更新1: 为了进一步澄清,这是我的目标:
由于 beforeShowDay 仅支持创建
title
属性的值,并且由于关闭引用以添加更多属性的技巧可能还不够,因为它是针对 td 而不是交互式元素,因此您可以只使用不同的策略来填充实际锚点上的 aria-label
属性。
您可以依赖选项
beforeShow
,它将运行在日期选择器实际显示之前一刻给出的函数:
https://api.jqueryui.com/datepicker/#option-beforeShow
演出前 类型:函数(元素输入,对象安装)
一个接受输入字段和当前日期选择器实例的函数 并返回一个选项对象来更新日期选择器。这是 在显示日期选择器之前调用。
这样的函数将迭代日历中包含用户可以选择的每一天(锚元素)的每个交互元素,并向其添加一个
aria-label
属性,其值来自其父单元格上的 title
属性(设置像你一样通过 beforeShowDay
)。
这是正在处理的日单元格的示例:
<td
class="ui-datepicker-days-cell-over ui-datepicker-current-day ui-datepicker-today"
title="February 9, 2024"
data-handler="selectDay"
data-event="click"
data-month="1"
data-year="2024">
<a
class="ui-state-default ui-state-highlight ui-state-active" href="#"
aria-label="February 9, 2024">9</a>
</td>
可以选择通过像这样从每个组件中挑选零件来制作日期,但这有点过分了:
const year = parentCell.attr('data-year');
const month = parentCell.attr('data-month');
const day = $(this).text();
const paddedMonth =
(parseInt(month, 10) + 1).toString().padStart(2, '0');
const paddedDay = day.padStart(2, '0');
//previously grab day info and format the correponding date
const formattedDate = `${paddedDay}/${paddedMonth}/${year}`;
//populate the day anchor with the aria-label containing dd/mm/yyyy
$(this).attr('aria-label', formattedDate);
作为进一步的操作,我还处理了
onSelect
事件,一旦在日期选择器中选择了日期,该事件就会将 aria-label
属性添加到输入元素中。可能不需要它,因为屏幕阅读器可能已经可以读取输入元素的值。
请使用屏幕阅读器提供反馈,以便我们了解
aria-label
是否足够或是否需要采取进一步措施。顺便说一句,样板现在已经非常成熟,可以处理添加更多信息,我们只需要了解哪些信息即可。
$(document).ready(function () {
$(".month-calendar input").datepicker({
showOtherMonths: true,
minDate: 0,
//on date selected
onSelect: function(dateText, inst) {
const value = "Selected date: " + dateText;
//set the aria-label of the input element with the date picked
$(this).attr("aria-label", value);
},
//before showing each day in the datepicker grid
beforeShowDay: function(date) {
//return a value used to populate the title attr of the day td
const dateString = $.datepicker.formatDate('MM d, yy', date);
return [true, '', dateString];
},
//before showing the days grid
beforeShow: function(input, inst){
//set timeout is to wait for the ui to be rendered
setTimeout(function() {
//select the calendar element
const daysGrid = $('#ui-datepicker-div .ui-datepicker-calendar');
//fetch all the anchors being interactive days
const interactiveDays = $(daysGrid).find('td a');
//for each one of them
interactiveDays.each(function(){
const parentCell = $(this).closest('td');
//set the aria-label as the same value on the title attr of its parent
$(this).attr('aria-label', $(parentCell).attr('title'));
//...other aria attributes could be set at this point...
});
});
}
}).datepicker("setDate", new Date());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="month-calendar">
<input type="text" id="datepicker">
</div>