一、為什麼要構建可訪問的組件
在開發web應用程序時,訪問性是非常重要的。Web內容應該對所有人都是可用的,無論他們的能力或技術水平如何。這意味著需要確保我們構建的應用程序能訪問到各種各樣的用戶,包括有殘障的用戶。
如果你需要構建一個級聯選擇器組件,那麼它必須是可訪問的,以確保每個人都可以使用它。用戶可以使用鍵盤導航,屏幕閱讀器等多種方式來與應用程序交互。
二、如何構建可訪問的級聯選擇器
構建可訪問的級聯選擇器時需要考慮以下問題:
1.表格結構
在使用React構建可訪問的級聯選擇器時,首先需要考慮如何為組件呈現表格結構。
class CascadingSelect extends React.Component {
render() {
const { options } = this.props;
return (
<table className="cascading-select">
<thead>
<tr>
<th>Option 1</th>
<th>Option 2</th>
<th>Option 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<select aria-label="Option 1" className="option-1">
{options.map(option => (
<option key={option.value} value={option.value}>{option.label}</option>
))}
</select>
</td>
<td>
<select aria-label="Option 2" className="option-2">
<option>Please select an option</option>
</select>
</td>
<td>
<select aria-label="Option 3" className="option-3">
<option>Please select an option</option>
</select>
</td>
</tr>
</tbody>
</table>
);
}
}
2.鍵盤導航
為了使級聯選擇器對於鍵盤用戶友好,需要進行正確的鍵盤導航。
使用方向鍵向上和向下瀏覽可選項,並且通過鍵盤選擇選項。在此過程中,UI需要提供正確的反饋,例如高亮所選項並將其保存為活動狀態。
當選擇過程完成後,級聯選擇器需要使新選擇的選項處於活動狀態,並將焦點設置為級聯選擇器下一個可操作單元格中的適當選項。
class CascadingSelect extends React.Component {
handleKeyDown = (e, column, row) => {
const { options, onChange } = this.props;
const activeOption = options[column][row];
const activeOptionIndex = options[column].indexOf(activeOption);
switch (e.keyCode) {
case 13: // Return
case 32: // Space
e.preventDefault();
onChange(column, row, activeOption.value);
break;
case 38: // Up arrow
e.preventDefault();
if (activeOptionIndex > 0) {
onChange(column, row, options[column][activeOptionIndex - 1].value);
}
break;
case 40: // Down arrow
e.preventDefault();
if (activeOptionIndex < options[column].length - 1) {
onChange(column, row, options[column][activeOptionIndex + 1].value);
}
break;
case 37: // Left arrow
e.preventDefault();
if (column > 0) {
const prevRow = options[column - 1].findIndex(option => option.value === options[column - 1][row].parent);
this[`select${column - 1}-${prevRow}`].focus();
}
break;
case 39: // Right arrow
e.preventDefault();
if (column < options.length - 1 && options[column + 1].some(option => option.parent === activeOption.value)) {
const nextRow = options[column + 1].findIndex(option => option.parent === activeOption.value);
this[`select${column + 1}-${nextRow}`].focus();
}
break;
default:
break;
}
};
render() {
const { options, values } = this.props;
return (
<table className="cascading-select">
...
<tbody>
{options[0].map((option, row) => (
<tr key={option.value}>
<td>
<select
aria-label="Option 1"
className="option-1"
>
{options[0].map(option => (
<option key={option.value} value={option.value} selected={values[0] === option.value}>
{option.label}
</option>
))}
</select>
</td>
{options.slice(1).map((column, columnIdx) => (
<td key={columnIdx}>
<select
aria-label={`Option ${columnIdx + 2}`}
className={`option-${columnIdx + 2}`}
disabled={values[columnIdx] === ''}
onChange={(e) => this.props.onChange(columnIdx + 1, row, e.target.value)}
onKeyDown={(e) => this.handleKeyDown(e, columnIdx + 1, row)}
value={values[columnIdx + 1]}
ref={(el) => { this[`select${columnIdx + 1}-${row}`] = el; }}
>
<option value="">Please select an option</option>
{column.filter(o => o.parent === values[columnIdx]).map(option => (
<option key={option.value} value={option.value} selected={values[columnIdx + 1] === option.value}>
{option.label}
</option>
))}
</select>
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
}
3.屏幕閱讀器
屏幕閱讀器將表格朗讀給殘障用戶,以使他們能夠使用級聯選擇器。
如果級聯選擇器中的選項值不像視覺用戶那樣易於識別,可以添加自定義aria-label來為屏幕閱讀器提供更多信息並更好地幫助殘障用戶使用級聯選擇器。
class CascadingSelect extends React.Component {
render() {
const { options } = this.props;
return (
<table className="cascading-select" aria-label="Cascading select">
...
<tbody>
{options[0].map((option, row) => (
<tr key={option.value}>
<td>
<label htmlFor={`option-1-${row}`} className="visually-hidden">Option 1</label>
<select
id={`option-1-${row}`}
aria-label="Option 1"
className="option-1"
>
...
</select>
</td>
{options.slice(1).map((column, columnIdx) => (
<td key={columnIdx}>
<label htmlFor={`option-${columnIdx + 2}-${row}`} className="visually-hidden">Option {columnIdx + 2}</label>
<select
id={`option-${columnIdx + 2}-${row}`}
aria-label={`Option ${columnIdx + 2}`}
className={`option-${columnIdx + 2}`}
disabled={values[columnIdx] === ''}
onChange={(e) => this.props.onChange(columnIdx + 1, row, e.target.value)}
onKeyDown={(e) => this.handleKeyDown(e, columnIdx + 1, row)}
value={values[columnIdx + 1]}
ref={(el) => { this[`select${columnIdx + 1}-${row}`] = el; }}
>
...
</select>
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
}
三、總結
在React中構建可訪問的級聯選擇器很重要,因為它確保您的web應用程序可以被儘可能多的用戶使用。通過使用簡單的表格結構,正確定義鍵盤導航,添加相關的aria-label和label元素,可以容易地創建可訪問的級聯選擇器。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/280616.html