scrollIntoViewIfNeeded 的行为
Behavior of scrollIntoViewIfNeeded
我正在努力创建一个网络组件,给定一个可聚焦的元素列表,自动具有可访问的键盘导航。
其中一部分是让活动元素滚动到视图中,如果它还没有,为此我正在使用 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>
centerIfNeeded
论点似乎根本没有受到尊重。有时它会在我第一次关注视口之外的元素时受到尊重,但第二次不会,有时它会被完全忽略。
这是预期的行为吗?
问题是默认情况下 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>
我正在努力创建一个网络组件,给定一个可聚焦的元素列表,自动具有可访问的键盘导航。
其中一部分是让活动元素滚动到视图中,如果它还没有,为此我正在使用 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>
centerIfNeeded
论点似乎根本没有受到尊重。有时它会在我第一次关注视口之外的元素时受到尊重,但第二次不会,有时它会被完全忽略。
这是预期的行为吗?
问题是默认情况下 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>