我正在创建一个web组件,在给定可聚焦元素列表的情况下,该组件自动具有可访问的键盘导航。
其中的一部分是让活动元素滚动到视图中(如果它还没有(,为此我使用了Element.scrollIntoViewIfNeeded
(在chrome中,所以支持应该不会有问题(。
我正在经历一些奇怪的行为,我不太明白。我创建了一个最小代码沙箱来显示这个问题。
const app = document.getElementById("app");
for (var i = 0; i < 100; i++) {
const paragraph = document.createElement("p");
paragraph.innerHTML = "element " + i;
paragraph.tabIndex = -1;
app.appendChild(paragraph);
}
const handleKeyDown = (event) => {
event.preventDefault();
switch (event.key) {
case "ArrowDown":
if (app.contains(document.activeElement)) {
const next = document.activeElement.nextElementSibling;
next.focus();
next.scrollIntoViewIfNeeded(false);
} else {
const first = app.firstElementChild;
first.focus();
first.scrollIntoViewIfNeeded(false);
}
break;
case "ArrowUp":
if (app.contains(document.activeElement)) {
const previous = document.activeElement.previousElementSibling;
previous.focus();
previous.scrollIntoViewIfNeeded(false);
} else {
const last = app.lastElementChild;
last.focus();
last.scrollIntoViewIfNeeded(false);
}
break;
default:
break;
}
};
document.addEventListener("keydown", handleKeyDown, false);
body {
font-family: sans-serif;
}
.app {
display: flex;
flex-direction: column;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app" class="app"></div>
<script src="src/index.js"></script>
</body>
</html>
CCD_ 2的论点似乎根本没有得到尊重。有时,我第一次聚焦视口外的元素时会尊重它,但第二次不会,有时它会被完全忽略。
这是预期的行为吗?
问题是,默认情况下,focus()
调用本身将在内部调用scrollIntoView()
,并且这两个调用将发生冲突
为了防止这种情况发生,您可以将{ preventScroll: true }
选项传递给对focus()
的呼叫。
const app = document.getElementById("app");
for (var i = 0; i < 100; i++) {
const paragraph = document.createElement("p");
paragraph.innerHTML = "element " + i;
paragraph.tabIndex = -1;
app.appendChild(paragraph);
}
const handleKeyDown = (event) => {
event.preventDefault();
switch (event.key) {
case "ArrowDown":
if (app.contains(document.activeElement)) {
const next = document.activeElement.nextElementSibling;
next?.focus({ preventScroll: true });
next?.scrollIntoViewIfNeeded(false);
} else {
const first = app.firstElementChild;
next?.focus({ preventScroll: true });
first?.scrollIntoViewIfNeeded(false);
}
break;
case "ArrowUp":
if (app.contains(document.activeElement)) {
const previous = document.activeElement.previousElementSibling;
previous?.focus({ preventScroll: true });
previous?.scrollIntoViewIfNeeded(false);
} else {
const last = app.lastElementChild;
last?.focus({ preventScroll: true });
last?.scrollIntoViewIfNeeded(false);
}
break;
default:
break;
}
};
document.addEventListener("keydown", handleKeyDown, false);
body {
font-family: sans-serif;
}
.app {
display: flex;
flex-direction: column;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app" class="app"></div>
<script src="src/index.js"></script>
</body>
</html>