在React中制作“ roving tabindex”的最简单方法是什么?基本上是在子元素之间切换焦点和tabindex=0/-1
。仅单个元素具有tabindex
中的0
,而其他元素接收-1
。箭头键在子元素之间切换tabindex
并对其进行聚焦。
现在,我对所需类型进行简单的子级映射,并设置index
prop并获取ref
,以便以后使用。它看起来很健壮,但是可能有更简单的解决方案吗?
我当前的解决方案(伪javascript,仅供参考)
ElementWithFocusManagement.js
function recursivelyMapElementsOfType(children, isRequiredType, getProps) {
return Children.map(children, function(child) {
if (isValidElement(child) === false) {return child;}
if (isRequiredType(child)) {
return cloneElement(
child,
// Return new props
// {
// index, iterated in getProps closure
// focusRef, saved to `this.focusable` aswell, w/ index above
// }
getProps()
);
}
if (child.props.children) {
return cloneElement(child, {
children: recursivelyMapElementsOfType(child.props.children, isRequiredType, getProps)
});
}
return child;
});
}
export class ElementWithFocusManagement {
constructor(props) {
super(props);
// Map of all refs, that should receive focus
// {
// 0: {current: HTMLElement}
// ...
// }
this.focusable = {};
this.state = {
lastInteractionIndex: 0
};
}
handleKeyDown() {
// Handle arrow keys,
// check that element index in `this.focusable`
// update state if it is
// focus element
}
render() {
return (
<div onKeyDown={this.handleKeyDown}>
<Provider value={{lastInteractionIndex: this.state.lastInteractionIndex}}>
{recursivelyMapElementsOfType(
children,
isRequiredType, // Check for required `displayName` match
getProps(this.focusable) // Get index, and pass ref, that would be saved to `this.focusable[index]`
)}
</Provider>
</div>
);
}
}
with-focus.js
export function withFocus(WrappedComponent) {
function Focus({index, focusRef, ...props}) {
return (
<Consumer>
{({lastInteractionIndex}) => (
<WrappedComponent
{...props}
elementRef={focusRef}
tabIndex={lastInteractionIndex === index ? 0 : -1}
/>
)}
</Consumer>
);
}
// We will match for this name later
Focus.displayName = `WithFocus(${WrappedComponent.name})`;
return Focus;
}
Anything.js
const FooWithFocus = withFocus(Foo);
<ElementWithFocusManagement> // Like toolbar, dropdown menu and etc.
<FooWithFocus>Hi there</FooWithFocus> // Button, menu item and etc.
<AnythingThatPreventSimpleMapping>
<FooWithFocus>How it's going?</FooWithFocus>
</AnythingThatPreventSimpleMapping>
<SomethingWithoutFocus />
</ElementWithFocusManagement>
答案 0 :(得分:0)
此库可能会帮助您:
https://www.npmjs.com/package/keyboard-navigator
它是一个可配置的选项卡和焦点管理库,还提供了箭头导航策略。
答案 1 :(得分:0)
react-roving-tabindex
看起来不错。