如何在 React 中像 google 驱动器这样的响应式卡片网格上进行箭头键导航?
How to make arrow key navigation on responsive card grid like google drive in React?
我已经尝试在所有 4 个方向上实现箭头键导航。我能够使用 nextSibling
和 previousSibling
实现 2 个方向 left
和 right
。但没有找到任何方法来获得高于和低于 divs。我见过很多在卡片网格布局上使用箭头键导航的示例,但发现没有一个采用响应式设计。当您有响应式支持时,每行中的卡片数量会发生变化。在我们的例子中,我们有一个 div 和 wrap 来创建网格。我见过像 Google drive 这样的应用程序,它们具有响应支持和箭头键导航。 Sample
如果您确定所有卡片的宽度都相同,您可以采用以下方法:
您可以使用它们的 x 和 y 坐标找到上方或下方的元素,您可以使用 Element.getBoundingClientRect() , window.scrollX and window.scrollY 方法获得这些元素。
继续您的 sample,
将 getRect() 方法添加到您的布局组件以获取 x 和 y 坐标。
getRect = (id) => {
const el = document.getElementById(id);
const rect = el.getBoundingClientRect();
const x = rect.left + window.scrollX;
const y = rect.top + window.scrollY;
return { el, x, y };
};
现在将 ARROW_UP
和 ARROW_DOWN
键的条件添加到 handleKeyPress()
方法
else if (e.key === NAVIGATION_KEYS.ARROW_UP) {
const { x, y } = this.getRect(selected);
// loop back in the list and select the first element
// that is above the current selected element and has the same x coordinate
for (let i = list.indexOf(selected) - 1; i >= 0; i--) {
const { el, x: tx, y: ty } = this.getRect(list[i]);
if (x === tx && y > ty) {
this.setState({
selected: list[i]
});
el.scrollIntoView(); // scrolls the element into view, try removing it to see what it does
break;
}
}
} else if (e.key === NAVIGATION_KEYS.ARROW_DOWN) {
const { x, y } = this.getRect(selected);
// loop forward in the list and select the first element
// that is below the current selected element and has the same x coordinate
for (let i = list.indexOf(selected) + 1; i < list.length; i++) {
const { el, x: tx, y: ty } = this.getRect(list[i]);
if (x === tx && y < ty) {
this.setState({
selected: list[i]
});
el.scrollIntoView(); // scrolls the element into view, try removing it to see what it does
break;
}
}
}
如果你想要流畅的滚动效果可以添加下面的css
html {
scroll-behaviour: smooth;
}
我加了注释解释,有不懂的地方可以问
分叉和扩展
我已经尝试在所有 4 个方向上实现箭头键导航。我能够使用 nextSibling
和 previousSibling
实现 2 个方向 left
和 right
。但没有找到任何方法来获得高于和低于 divs。我见过很多在卡片网格布局上使用箭头键导航的示例,但发现没有一个采用响应式设计。当您有响应式支持时,每行中的卡片数量会发生变化。在我们的例子中,我们有一个 div 和 wrap 来创建网格。我见过像 Google drive 这样的应用程序,它们具有响应支持和箭头键导航。 Sample
如果您确定所有卡片的宽度都相同,您可以采用以下方法:
您可以使用它们的 x 和 y 坐标找到上方或下方的元素,您可以使用 Element.getBoundingClientRect() , window.scrollX and window.scrollY 方法获得这些元素。
继续您的 sample,
将 getRect() 方法添加到您的布局组件以获取 x 和 y 坐标。
getRect = (id) => {
const el = document.getElementById(id);
const rect = el.getBoundingClientRect();
const x = rect.left + window.scrollX;
const y = rect.top + window.scrollY;
return { el, x, y };
};
现在将 ARROW_UP
和 ARROW_DOWN
键的条件添加到 handleKeyPress()
方法
else if (e.key === NAVIGATION_KEYS.ARROW_UP) {
const { x, y } = this.getRect(selected);
// loop back in the list and select the first element
// that is above the current selected element and has the same x coordinate
for (let i = list.indexOf(selected) - 1; i >= 0; i--) {
const { el, x: tx, y: ty } = this.getRect(list[i]);
if (x === tx && y > ty) {
this.setState({
selected: list[i]
});
el.scrollIntoView(); // scrolls the element into view, try removing it to see what it does
break;
}
}
} else if (e.key === NAVIGATION_KEYS.ARROW_DOWN) {
const { x, y } = this.getRect(selected);
// loop forward in the list and select the first element
// that is below the current selected element and has the same x coordinate
for (let i = list.indexOf(selected) + 1; i < list.length; i++) {
const { el, x: tx, y: ty } = this.getRect(list[i]);
if (x === tx && y < ty) {
this.setState({
selected: list[i]
});
el.scrollIntoView(); // scrolls the element into view, try removing it to see what it does
break;
}
}
}
如果你想要流畅的滚动效果可以添加下面的css
html {
scroll-behaviour: smooth;
}
我加了注释解释,有不懂的地方可以问
分叉和扩展