Javascript 递增时获取重复项&;使用带有React JS的箭头键进行递减

Javascript 递增时获取重复项&;使用带有React JS的箭头键进行递减,javascript,reactjs,increment,arrow-keys,Javascript,Reactjs,Increment,Arrow Keys,我又回到了这个问题上,试图通过菜单增加/减少,然后我的头就要穿过墙壁,弄明白这一点。我感觉我就快到了,但是错过了一些东西。在我单击按钮之前,我无法向右箭头,而且我单击的按钮不会删除该类。任何帮助都将不胜感激 按钮js: ... class Button extends Component { onClick() { const { label, onClick } = this.props; onClick(label); } render() { con

我又回到了这个问题上,试图通过菜单增加/减少,然后我的头就要穿过墙壁,弄明白这一点。我感觉我就快到了,但是错过了一些东西。在我单击按钮之前,我无法向右箭头,而且我单击的按钮不会删除该类。任何帮助都将不胜感激

按钮js:

...

class Button extends Component {
  onClick() {
    const { label, onClick } = this.props;
    onClick(label);
  }

  render() {
    const {
      onClick,
      props: { activeTab, label, tab, className }
    } = this;
    let ariaSelected = "";
    if (activeTab === label || className === "active") {
      ariaSelected += "true";
    }
    return (
      <li role="presentation">
        <a
          className={className}
          aria-selected={ariaSelected ? "true" : undefined} 
          onClick={e => this.onClick(e)}
          role="tab"
          id={"tab" + tab}
          //tabIndex="-1"
        >
          {label}
        </a>
      </li>
    );
  }
}

..
。。。
类按钮扩展组件{
onClick(){
const{label,onClick}=this.props;
onClick(标签);
}
render(){
常数{
onClick,
道具:{activeTab,label,tab,className}
}=这个;
让我们选择“”;
if(activeTab==label | | className==“active”){
所选参数+=“真”;
}
返回(
  • this.onClick(e)} role=“tab” id={“tab”+tab} //tabIndex=“-1” > {label}
  • ); } } ..
    菜单Js:

    class Menu extends Component {
      constructor(props) {
        super(props);
        this.state = {
          activeTab: this.props.children[0].props.label,
          cursor: 0
        };
        this.handleKeyDown = this.handleKeyDown.bind(this);
      }
    
      componentDidMount() {
        document.addEventListener("keydown", this.handleKeyDown, false);
      }
    
      componentWillUnmount() {
        document.removeEventListener("keydown", this.handleKeyDown, false);
      }
    
      handleKeyDown(e) {
        const { cursor } = this.state;
        const cnt = React.Children.count(this.props.children);
        if (e.keyCode === 37 && cursor > 0) {
          this.setState(prevState => ({
            cursor: prevState.cursor - 1
          }));
          console.log(cursor);
        } else if (e.keyCode === 39 && cursor < cnt - 1) {
          this.setState(prevState => ({
            cursor: prevState.cursor + 1
          }));
          console.log(cursor);
        }
      }
    
      onClickTabItem = tab => {
        this.setState({
          activeTab: tab
        });
      };
    
      render() {
        const {
          onClickTabItem,
          props: { children },
          state: { activeTab, cursor, className }
        } = this;
    
        return (
          <div className="tabbed">
            <ul role="tablist">
              {children.map((child, i) => {
                const { label, className } = child.props;
                return (
                  <Tab
                    activeTab={activeTab}
                    key={label}
                    label={label}
                    onClick={onClickTabItem}
                    tab={i}
                    className={ cursor === i || activeTab === label ? "active" : null}
                  />
                );
              })}
            </ul>
            <div className="tab-content">
              {children.map(child => {
                //if tab has label or active set, otherwise do nohthing
                if (child.props.label !== activeTab) return undefined;
                return child.props.children;
              })}
            </div>
          </div>
        );
      }
    }
    
    类菜单扩展组件{
    建造师(道具){
    超级(道具);
    此.state={
    activeTab:this.props.children[0].props.label,
    光标:0
    };
    this.handleKeyDown=this.handleKeyDown.bind(this);
    }
    componentDidMount(){
    document.addEventListener(“keydown”,this.handleKeyDown,false);
    }
    组件将卸载(){
    document.removeEventListener(“keydown”,this.handleKeyDown,false);
    }
    handleKeyDown(e){
    const{cursor}=this.state;
    const cnt=React.Children.count(this.props.Children);
    如果(e.keyCode==37&&cursor>0){
    this.setState(prevState=>({
    游标:prevState.cursor-1
    }));
    console.log(游标);
    }否则如果(e.keyCode===39&&cursor({
    游标:prevState.cursor+1
    }));
    console.log(游标);
    }
    }
    onClickTabItem=tab=>{
    这是我的国家({
    活动选项卡:选项卡
    });
    };
    render(){
    常数{
    关于这个项目,
    道具:{儿童},
    状态:{activeTab,游标,类名}
    }=这个;
    返回(
    
      {children.map((child,i)=>{ const{label,className}=child.props; 返回( ); })}
    {children.map(child=>{ //如果选项卡具有标签或活动集,则不执行任何操作 if(child.props.label!==activeTab)返回未定义; 返回child.props.children; })} ); } }
    当按下箭头键时,您可以从activeTab中获取标签号,而无需使用光标变量:

      handleKeyDown(e) {
        const cnt = React.Children.count(this.props.children);
        const pos = ~~this.state.activeTab[8]  // get current position
        if (e.keyCode === 37 && pos > 1) {
          this.setState({
            activeTab: "Section " + (pos - 1)
          });
        } else if (e.keyCode === 39 && pos < cnt) {
          this.setState({
            activeTab: "Section " + (pos + 1)
          });
        }
      }
    

    上面有相当多的重复和不必要的代码。我花了一些时间进行重构,使其更模块化/更易于使用

    工作示例:

    变化:

    • Tabs
      的作用类似于多个
      Tab
      组件的容器
    • 选项卡
      是一个简单的可重用组件,需要
      标题
      子项
    • 现在,所有选项卡都由
      activeTab
      状态管理,并与映射的
      键进行比较(对于唯一的
      id
      ,可以很容易地更改/实现)
    • 利用
      prevProps.children.length
      确定
      setState
      回调中的选项卡长度
    • TabPane
      a
      (链接元素)更改为
      b
      (未格式化的文本元素),因为使用相同的
      role=“tablist”
    • 添加了
      换行:断开单词
      TabBody
      中的
      a
      元素,以防止它们破坏小屏幕的
      部分
    index.js

    import React from "react";
    import { render } from "react-dom";
    import Tabs, { Tab } from "./components/Tabs";
    import "./styles.css";
    
    const App = () => (
      <Tabs>
        <Tab title="Section 1">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam euismod,
          tortor nec pharetra ultricies, ante erat imperdiet velit, nec laoreet enim
          lacus a velit.<a href="#">Nam luctus</a>, enim in interdum condimentum,
          nisl diam iaculis lorem, vel volutpat mi leo sit amet lectus. Praesent non
          odio bibendum magna bibendum accumsan.
        </Tab>
        <Tab title="Section 2">
          Nullam at diam nec arcu suscipit auctor non a erat. Sed et magna semper,
          eleifend magna non, facilisis nisl. Proin et est et lorem dictum finibus
          ut nec turpis. Aenean nisi tortor, euismod a mauris a, mattis scelerisque
          tortor. Sed dolor risus, varius a nibh id, condimentum lacinia est. In
          lacinia cursus odio a aliquam. Curabitur tortor magna, laoreet ut rhoncus
          at, sodales consequat
        </Tab>
        <Tab title="Section 3">
          Phasellus ac tristique orci. Nulla maximus
          <a href="">justo nec dignissim consequat</a>. Sed vehicula diam sit amet
          mi efficitur vehicula in in nisl. Aliquam erat volutpat. Suspendisse lorem
          turpis, accumsan consequat consectetur gravida,
          <a href="#">pellentesque ac ante</a>. Aliquam in commodo ligula, sit amet
          mollis neque. Vestibulum at facilisis massa.
        </Tab>
        <Tab title="Section 4">
          Nam luctus, enim in interdum condimentum, nisl diam iaculis lorem, vel
          volutpat mi leo sit amet lectus. Praesent non odio bibendum magna bibendum
          accumsan. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam
          euismod, tortor nec pharetra ultricies, ante erat imperdiet velit, nec
          laoreet enim lacus a velit.
        </Tab>
      </Tabs>
    );
    
    render(<App />, document.getElementById("root"));
    
    import React, { Component } from "react";
    import PropTypes from "prop-types";
    import TabPane from "./TabPane";
    import TabBody from "./TabBody";
    
    export const Tab = ({ title, children }) => <div tab={title}>{children}</div>;
    
    Tab.propTypes = {
      children: PropTypes.node.isRequired,
      title: PropTypes.string.isRequired
    };
    
    class Tabs extends Component {
      state = { activeTab: 0 };
    
      componentDidMount = () => {
        document.addEventListener("keydown", this.handleKeyPress, false);
        window.focus();
      }
    
      componentWillUnmount = () =>
        document.removeEventListener("keydown", this.handleKeyPress, false);
    
      handleClickTabItem = ({ target: { id } }) =>
        this.setState({ activeTab: ~~id });
    
      handleKeyPress = ({ keyCode }) => {
        if (keyCode === 37 || keyCode === 39) {
          this.setState((prevState, prevProps) => {
            const nextTab = keyCode === 37 
              ? prevState.activeTab - 1 
              : prevState.activeTab + 1;
    
            return nextTab >= 0 && nextTab < prevProps.children.length
              ? { activeTab: nextTab }
              : null;
          });
        }
      };
    
      render = () => {
        const { activeTab } = this.state;
        const { children } = this.props;
        return (
          <div className="tabbed">
            <ul role="tablist">
              {children.map(({ props }, key) => (
                <TabPane
                  key={key}
                  activeTab={activeTab}
                  onClickTabItem={this.handleClickTabItem}
                  id={key}
                  {...props}
                />
              ))}
              <div className="tab-content">
                {children.map(({ props }, key) =>
                  key === activeTab ? (
                    <TabBody key={key} id={key} {...props} />
                  ) : null
                )}
              </div>
            </ul>
          </div>
        );
      };
    }
    
    Tabs.propTypes = {
      children: PropTypes.node.isRequired
    };
    
    export default Tabs;
    
    import React from "react";
    import PropTypes from "prop-types";
    
    const TabPane = ({ activeTab, id, onClickTabItem, title, ...rest }) => (
      <li role="presentation">
        <b
          id={id}
          aria-selected={activeTab === id ? "true" : null}
          onClick={onClickTabItem}
          role="tab"
          {...rest}
        >
          {title}
        </b>
      </li>
    );
    
    TabPane.propTypes = {
      activeTab: PropTypes.number.isRequired,
      id: PropTypes.number.isRequired,
      onClickTabItem: PropTypes.func.isRequired,
      title: PropTypes.string.isRequired
    };
    
    export default TabPane;
    
    import React from "react";
    import PropTypes from "prop-types";
    
    const TabBody = ({ title, id, children }) => (
      <section id={id} role="tabpanel" tabIndex="-1" aria-labelledby={id}>
        <h2>{title}</h2>
        <div>{children}</div>
      </section>
    );
    
    TabBody.propTypes = {
      children: PropTypes.node.isRequired,
      id: PropTypes.number.isRequired,
      title: PropTypes.string.isRequired
    };
    
    export default TabBody;
    
    body {
      max-width: 40rem;
      padding: 0 1rem;
      font-size: 125%;
      line-height: 1.5;
      margin: 1.5rem auto;
      font-family: "Lato", Arial, sans-serif;
      font-size: 16px;
    }
    
    * {
      color: inherit;
      margin: 0;
    }
    
    [role="tablist"] {
      padding: 0;
    }
    
    [role="tablist"] li,
    [role="tablist"] b {
      display: inline-block;
    }
    
    [role="tablist"] b {
      text-decoration: none;
      padding: 0.5rem 1em;
      cursor: pointer;
    }
    
    [role="tablist"] a {
      text-decoration: none;
      padding-left: 0.2rem;
      word-wrap: break-word;
    }
    
    [role="tablist"] [aria-selected] {
      border: 2px solid;
      background: #fff;
      border-bottom: 0;
      position: relative;
      top: 2px;
    }
    
    [role="tabpanel"] {
      border: 2px solid;
      padding: 1.5rem;
    }
    
    [role="tabpanel"] * + * {
      margin-top: 0.75rem;
    }
    
    *:focus {
      outline: none;
      box-shadow: inset 0 0 0 4px lightBlue;
    }
    
    @media (max-width: 550px) {
      [role="tablist"] li,
      [role="tablist"] b {
        display: block;
        position: static;
      }
    
      [role="tablist"] b {
        border: 2px solid #222 !important;
      }
    
      [role="tablist"] li + li b {
        border-top: 0 !important;
      }
    
      [role="tablist"] [aria-selected] {
        position: static;
      }
    
      [role="tablist"] [aria-selected]::after {
        content: "\0020⬅";
      }
    
      [role="tabpanel"] {
        border-top: 0;
      }
    }
    
    section a {
      color: rgb(66, 133, 244);
    }
    

    @oMiKeY-绝对传奇伴侣。顺便问一下,“~~”是什么?这是我喜欢做的一个小捷径,它比parseInt()更有趣。它将一个字符串数字转换成整数。还有一件事。没有点击按钮,用箭头键把它放到标签上,我缺少了什么?但是,它工作得很好,只是在第一次单击按钮之前不会启动。请尝试放置
    window.focus()位于索引底部。js@user992731我把它改干净了一点,以防你打算换标签。现在他们不必有数字或任何东西。
    
    body {
      max-width: 40rem;
      padding: 0 1rem;
      font-size: 125%;
      line-height: 1.5;
      margin: 1.5rem auto;
      font-family: "Lato", Arial, sans-serif;
      font-size: 16px;
    }
    
    * {
      color: inherit;
      margin: 0;
    }
    
    [role="tablist"] {
      padding: 0;
    }
    
    [role="tablist"] li,
    [role="tablist"] b {
      display: inline-block;
    }
    
    [role="tablist"] b {
      text-decoration: none;
      padding: 0.5rem 1em;
      cursor: pointer;
    }
    
    [role="tablist"] a {
      text-decoration: none;
      padding-left: 0.2rem;
      word-wrap: break-word;
    }
    
    [role="tablist"] [aria-selected] {
      border: 2px solid;
      background: #fff;
      border-bottom: 0;
      position: relative;
      top: 2px;
    }
    
    [role="tabpanel"] {
      border: 2px solid;
      padding: 1.5rem;
    }
    
    [role="tabpanel"] * + * {
      margin-top: 0.75rem;
    }
    
    *:focus {
      outline: none;
      box-shadow: inset 0 0 0 4px lightBlue;
    }
    
    @media (max-width: 550px) {
      [role="tablist"] li,
      [role="tablist"] b {
        display: block;
        position: static;
      }
    
      [role="tablist"] b {
        border: 2px solid #222 !important;
      }
    
      [role="tablist"] li + li b {
        border-top: 0 !important;
      }
    
      [role="tablist"] [aria-selected] {
        position: static;
      }
    
      [role="tablist"] [aria-selected]::after {
        content: "\0020⬅";
      }
    
      [role="tabpanel"] {
        border-top: 0;
      }
    }
    
    section a {
      color: rgb(66, 133, 244);
    }