使用 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 进一步访问相邻列表。