使用 React JSX 模拟 onFocus 和遍历节点
Emulate onFocus and traverse Nodes with React JSX
我想在 React 组件中模拟 Tab 事件,仅使用向下箭头键。
乍一看这似乎很简单,因为它是使用 ref callbacks 的单个输入。但是,我将拥有三个搜索结果列表 li,其中包含一个 href。
有没有人有比下面更好的方法?
P.S:我知道,为什么要重新创建选项卡功能? ... 客户要求! :-(
一点示例代码:
import React, { Component } from "react"
export default class TestList extends Component {
constructor(props){
super(props);
this.state = {
focusedItem: 0,
}
this.nextFocus = this.nextFocus.bind(this)
this.handleKey = this.handleKey.bind(this)
};
componentDidMount() {
const list = this.refs.list.children
if (list.length > 0) {
let item = list[0]
// console.log(item.id)
// console.log(item.tabIndex)
let current = item.tabIndex
this.setState({
focusedItem: current,
})
item.getDOMNode().focus();
}
}
upState() {
if (this.state.focusedItem === 0) {
this.setState({
focusedItem: 1,
});
}
else {
let current = this.state.focusedItem
let nextState = current+1
console.log(nextState)
this.setState({
focusedItem: nextState,
});
}
}
nextFocus() {
const list = this.refs.list.children
this.upState();
const item = list[this.state.focusedItem]
console.log(item)
if (this.state.focusedItem < list.length) {
item.getDOMNode().focus();
}
}
handleKey(event) {
switch(event.keyCode){
case 9: // Enter key
break;
case 13: // Enter key
break;
case 27: // Esc key
break;
case 32: // spacebar
break;
case 37: // left
break;
case 38: // up
break;
case 39: // right
this.nextFocus();
break;
case 40: // down
this.nextFocus();
// React.findDOMNode() ???
//onFocus DOMEventTarget relatedTarget
break;
default:
}
}
render() {
const navList = [
{
name:'please',
link:'/#',
}, {
name:'please 2',
link:'/#'
}, {
name:'please 3',
link:'/#'
}, {
name:'please 4',
link:'/#'
}
];
return (
<ul ref='list'>
{ navList.map((item, index) => {
return (
<li key={index}
ref={'lidx'+index}
id={'elid-'+index}
onClick={ this.focus }
tabIndex={index}
onKeyDown={this.handleKey} >
<b>{item.name}</b>
</li>
);
})}
</ul>
)
}
}
最近遇到类似的问题,用event.target
在节点间遍历。这样的事情对我有用:
handleKey (e) {
switch(e.keyCode) {
//...
case 38: // up
if (e.target.previousSibling) e.target.previousSibling.focus()
break
case 40: // down
if (e.target.nextSibling) e.target.nextSibling.focus()
break
//...
}
我不知道这是否被认为是一种不好的做法,或者它是否可以完全解决您的问题,但是使用它您不需要将当前关注的项目保持在状态中,也不需要使用参考。
您还可以使用 e.target.parentNode.nextSibling
进一步访问相邻列表。
我想在 React 组件中模拟 Tab 事件,仅使用向下箭头键。
乍一看这似乎很简单,因为它是使用 ref callbacks 的单个输入。但是,我将拥有三个搜索结果列表 li,其中包含一个 href。
有没有人有比下面更好的方法?
P.S:我知道,为什么要重新创建选项卡功能? ... 客户要求! :-(
一点示例代码:
import React, { Component } from "react"
export default class TestList extends Component {
constructor(props){
super(props);
this.state = {
focusedItem: 0,
}
this.nextFocus = this.nextFocus.bind(this)
this.handleKey = this.handleKey.bind(this)
};
componentDidMount() {
const list = this.refs.list.children
if (list.length > 0) {
let item = list[0]
// console.log(item.id)
// console.log(item.tabIndex)
let current = item.tabIndex
this.setState({
focusedItem: current,
})
item.getDOMNode().focus();
}
}
upState() {
if (this.state.focusedItem === 0) {
this.setState({
focusedItem: 1,
});
}
else {
let current = this.state.focusedItem
let nextState = current+1
console.log(nextState)
this.setState({
focusedItem: nextState,
});
}
}
nextFocus() {
const list = this.refs.list.children
this.upState();
const item = list[this.state.focusedItem]
console.log(item)
if (this.state.focusedItem < list.length) {
item.getDOMNode().focus();
}
}
handleKey(event) {
switch(event.keyCode){
case 9: // Enter key
break;
case 13: // Enter key
break;
case 27: // Esc key
break;
case 32: // spacebar
break;
case 37: // left
break;
case 38: // up
break;
case 39: // right
this.nextFocus();
break;
case 40: // down
this.nextFocus();
// React.findDOMNode() ???
//onFocus DOMEventTarget relatedTarget
break;
default:
}
}
render() {
const navList = [
{
name:'please',
link:'/#',
}, {
name:'please 2',
link:'/#'
}, {
name:'please 3',
link:'/#'
}, {
name:'please 4',
link:'/#'
}
];
return (
<ul ref='list'>
{ navList.map((item, index) => {
return (
<li key={index}
ref={'lidx'+index}
id={'elid-'+index}
onClick={ this.focus }
tabIndex={index}
onKeyDown={this.handleKey} >
<b>{item.name}</b>
</li>
);
})}
</ul>
)
}
}
最近遇到类似的问题,用event.target
在节点间遍历。这样的事情对我有用:
handleKey (e) {
switch(e.keyCode) {
//...
case 38: // up
if (e.target.previousSibling) e.target.previousSibling.focus()
break
case 40: // down
if (e.target.nextSibling) e.target.nextSibling.focus()
break
//...
}
我不知道这是否被认为是一种不好的做法,或者它是否可以完全解决您的问题,但是使用它您不需要将当前关注的项目保持在状态中,也不需要使用参考。
您还可以使用 e.target.parentNode.nextSibling
进一步访问相邻列表。