【问题标题】:REACT - toggle class onclickREACT - 切换类 onclick
【发布时间】:2017-07-26 14:37:00
【问题描述】:

我正在尝试弄清楚如何切换活动类 onClick 以更改 CSS 属性。

我采取了许多方法,并阅读了许多 SO 答案。使用 jquery 会相对简单,但是,我不知道用 react 来做到这一点。我的代码如下。谁能建议我应该怎么做?

如果不为每个项目创建新组件,是否可以这样做?

class Test extends Component(){

    constructor(props) {

    super(props);
    this.addActiveClass= this.addActiveClass.bind(this);

  }

  addActiveClass() {

    //not sure what to do here

  }

    render() {
    <div>
      <div onClick={this.addActiveClass}>
        <p>1</p>
      </div>
      <div onClick={this.addActiveClass}>
        <p>2</p>
      </div>
        <div onClick={this.addActiveClass}>
        <p>3</p>
      </div>
    </div>
  }

}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    使用状态。 Reacts 文档是 here

    class MyComponent extends Component {
        constructor(props) {
            super(props);
            this.addActiveClass= this.addActiveClass.bind(this);
            this.state = {
                active: false,
            };
        }
        toggleClass() {
            const currentState = this.state.active;
            this.setState({ active: !currentState });
        };
    
        render() {
            return (
                <div 
                    className={this.state.active ? 'your_className': null} 
                    onClick={this.toggleClass} 
                >
                    <p>{this.props.text}</p>
                </div>
            )
      }
    }
    
    class Test extends Component {
        render() {
            return (
                <div>
                    <MyComponent text={'1'} />
                    <MyComponent text={'2'} />
                </div>
            );
        }
    }
    

    【讨论】:

    • 有没有办法在不创建额外组件的情况下做到这一点?
    • 您想将复杂的组件分解成更小的组件,请参阅facebook.github.io/react/docs/…
    • 我已经分解了组件,但这仍然会在单击时为每个元素添加active。我只希望一个元素有一个活动类
    • 这不能称为切换的“活动”类,因为其他元素的活动类仍然存在。
    • 能否请您更新答案以使用onClick,而不是所有小写,因为您不正确
    【解决方案2】:

    您也可以使用hooks 执行此操作。

    function MyComponent (props) {
      const [isActive, setActive] = useState(false);
    
      const toggleClass = () => {
        setActive(!isActive);
      };
    
      return (
        <div 
          className={isActive ? 'your_className': null} 
          onClick={toggleClass} 
        >
          <p>{props.text}</p>
        </div>
       );
    }  
    

    【讨论】:

    • 感谢您添加此答案。我遇到了两个类和 isActive 的问题? 'your_className': null 这有帮助。
    【解决方案3】:

    我更喜欢在内联 if 语句中使用“&&”-运算符。在我看来,它以这种方式提供了更清晰的代码库。

    通常你可以做这样的事情

    render(){
    return(
      <div>
        <button className={this.state.active && 'active'}
          onClick={ () => this.setState({active: !this.state.active}) }>Click me</button>
      </div>
    )
    }
    

    请记住箭头函数是 ES6 特性,并记得在类 constructor() 中设置 'this.state.active' 值{}

    this.state = { active: false }
    

    或者如果你想在 JSX 中注入 css,你可以这样做

    <button style={this.state.active && style.button} >button</button>
    

    你可以声明样式 json 变量

    const style = { button: { background:'red' } }
    

    记住在 JSX 样式表上使用 camelCase。

    【讨论】:

      【解决方案4】:

      好吧,您的 addActiveClass 需要知道点击了什么。这样的事情可能会起作用(请注意,我已经添加了 div 作为状态数组处于活动状态的信息,并且 onClick 现在将单击的信息作为参数传递,之后状态会相应更新 - 当然有更聪明的方法来这样做,但你明白了)。

      class Test extends Component(){
      
        constructor(props) {
          super(props);
          this.state = {activeClasses: [false, false, false]};
          this.addActiveClass= this.addActiveClass.bind(this);
        }
      
        addActiveClass(index) {
          const activeClasses = [...this.state.activeClasses.slice(0, index), !this.state.activeClasses[index], this.state.activeClasses.slice(index + 1)].flat();
          this.setState({activeClasses});
        }
      
        render() {
          const activeClasses = this.state.activeClasses.slice();
          return (
            <div>
              <div className={activeClasses[0]? "active" : "inactive"} onClick={() => this.addActiveClass(0)}>
                <p>0</p>
              </div>
              <div className={activeClasses[1]? "active" : "inactive"} onClick={() => this.addActiveClass(1)}>
                <p>1</p>
              </div>
                <div  onClick={() => this.addActiveClass(2)}>
                <p>2</p>
              </div>
            </div>
          );
        }
      }
      

      【讨论】:

        【解决方案5】:

        React 有组件状态的概念,所以如果你想切换它,做一个setState

        constructor(props) {
          super(props);
        
          this.addActiveClass= this.addActiveClass.bind(this);
          this.state = {
            isActive: false
          }
        }
        
        addActiveClass() {
          this.setState({
            isActive: true
          })
        }
        

        在您的组件中使用this.state.isActive 来呈现您需要的内容。

        当您想在组件#1 中设置状态并在组件#2 中使用它时,这会变得更加复杂。只需深入研究 React 单向数据流和可能会帮助您处理它的 redux。

        【讨论】:

        • 我了解state 但这仍然不能真正解释单击元素时如何更新类名
        • 在您的 jsx 标记中执行 - &lt;div className={this.state.isActive ? 'active' : ''}&gt;。它是关于条件渲染的,但仍然依赖于状态。
        • 但这会在点击时将活动类添加到每个项目。我只希望单击的项目具有active 类名
        • 为什么每个项目?它会将类添加到您为其添加条件的项目中。理想情况下,您的项目应抽象为 Item 组件。然后,您将包含它 3 次,基本上会有 3 个项目,每个项目都有自己的 isActive 状态。是你的意思吗?
        • 不将其拆分为Item 组件有没有办法做到这一点?
        【解决方案6】:

        使用 React 你可以将切换类添加到任何 id/元素,试试

        style.css

        .hide-text{
            display: none !important;
            /* transition: 2s all ease-in 0.9s; */
          }
        .left-menu-main-link{
            transition: all ease-in 0.4s;
        }
        .leftbar-open{
            width: 240px;
            min-width: 240px;
            /* transition: all ease-in 0.4s; */
        }
        .leftbar-close{
            width: 88px;
            min-width:88px;
            transition: all ease-in 0.4s;
        }
        

        文件名.js

        ......
            ToggleMenu=()=>{
                     this.setState({
                        isActive: !this.state.isActive
                      })
                      console.log(this.state.isActive)
                }
                render() {
                    return (
                        <div className={this.state.isActive===true ? "left-panel leftbar-open" : "left-panel leftbar-close"} id="leftPanel">
                            <div className="top-logo-container"  onClick={this.ToggleMenu}>
                                    <span className={this.state.isActive===true ? "left-menu-main-link hide-from-menu" : "hide-text"}>Welcome!</span>
                            </div>
        
                            <div className="welcome-member">
                                <span className={this.state.isActive===true ? "left-menu-main-link hide-from-menu" : "hide-text"}>Welcome<br/>SDO Rizwan</span>
                            </div>
            )
            }
        ......
        

        【讨论】:

        • 我想补充一点,如果您不想为每个“isActive”语句定义一个静态类,您可以使用以下代码样式:@987654323 @
        【解决方案7】:

        以上答案都可以,但如果您想要不同的方法,请尝试类名:https://github.com/JedWatson/classnames

        【讨论】:

          【解决方案8】:

          A good sample 将有助于更好地理解事物:

          HTML

          <div id="root">
          </div>
          

          CSS

          .box {
            display: block;
            width: 200px;
            height: 200px;
            background-color: gray;
            color: white;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
          }
          .box.green {
            background-color: green; 
          }
          

          反应代码

          class App extends React.Component {
            constructor(props) {
              super(props);
              this.state = {addClass: false}
            }
            toggle() {
              this.setState({addClass: !this.state.addClass});
            }
            render() {
              let boxClass = ["box"];
              if(this.state.addClass) {
                boxClass.push('green');
              }
              return(
                  <div className={boxClass.join(' ')} onClick={this.toggle.bind(this)}>{this.state.addClass ? "Remove a class" : "Add a class (click the box)"}<br />Read the tutorial <a href="http://www.automationfuel.com" target="_blank">here</a>.</div>       
              );
            }
          }
          ReactDOM.render(<App />, document.getElementById("root"));
          

          【讨论】:

            【解决方案9】:

            您可以添加切换类或点击切换状态

            class Test extends Component(){
              state={
              active:false, 
             }
              toggleClass() {
                console.log(this.state.active)
                this.setState=({
                 active:true,
               })
              }
            
                render() {
                <div>
                  <div onClick={this.toggleClass.bind(this)}>
                    <p>1</p>
                  </div>
                </div>
              }
            
            }
            

            【讨论】:

              【解决方案10】:

              感谢@cssko 提供正确答案,但如果您自己尝试过,您会发现它不起作用。 @Matei Radu 提出了一个建议,但被 @cssko 拒绝,因此代码仍然无法运行(它会抛出错误“无法读取未定义的属性绑定”)。以下是正确的答案:

              class MyComponent extends React.Component {
                constructor(props) {
                  super(props);
                  this.addActiveClass = this.addActiveClass.bind(this);
                  this.state = {
                    active: false,
                  };
                }
                addActiveClass() {
                  const currentState = this.state.active;
                  this.setState({
                    active: !currentState
                  });
                };
              
                render() {
                  return ( <
                    div className = {
                      this.state.active ? 'your_className' : null
                    }
                    onClick = {
                      this.addActiveClass
                    } >
                    <
                    p > {
                      this.props.text
                    } < /p> < /
                    div >
                  )
                }
              }
              
              class Test extends React.Component {
                render() {
                  return ( <
                    div >
                    <
                    MyComponent text = {
                      'Clicking this will toggle the opacity through css class'
                    }
                    /> < /
                    div >
                  );
                }
              }
              
              ReactDOM.render( <
                Test / > ,
                document.body
              );
              .your_className {
                opacity: 0.3
              }
              <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

              【讨论】:

                【解决方案11】:

                React 有组件状态的概念,所以如果要 Toggle,使用 setState:

                1. App.js
                import React from 'react';
                
                import TestState from './components/TestState';
                
                class App extends React.Component {
                  render() {
                    return (
                      <div className="App">
                        <h1>React State Example</h1>
                        <TestState/>
                      </div>
                    );
                  }
                }
                
                export default App;
                
                1. components/TestState.js
                import React from 'react';
                
                class TestState extends React.Component
                {
                
                    constructor()
                    {
                        super();
                        this.state = {
                            message: 'Please subscribe',
                            status: "Subscribe"
                        }
                    }
                
                    changeMessage()
                    {
                        if (this.state.status === 'Subscribe')
                        {
                            this.setState({message : 'Thank You For Scubscribing.', status: 'Unsubscribe'})
                        }
                        else
                        {
                            this.setState({ message: 'Please subscribe', status: 'Subscribe' })
                        }
                    }
                    
                    render()
                    {
                        return (
                            <div>
                                <h1>{this.state.message}</h1>
                        <button onClick={()=> this.changeMessage() } >{this.state.status}</button>
                            </div>
                        )
                    }
                }
                
                export default TestState;
                
                1. 输出

                【讨论】:

                  【解决方案12】:

                  我最近开始学习 React,想建立一个标签来看看我的知识已经走了多远。我遇到了这个并决定在没有 redux 的情况下实现一些东西。我觉得答案并不能反映 op 想要达到的目标。他只想要一个活动组件,但这里的答案将使所有组件都处于活动状态。我试了一下。

                  下面是标签文件

                  import React, { Component } from 'react';
                  
                  
                  class Tab extends Component {
                  
                      render(){
                          const tabClassName = "col-xs-3 tab-bar";
                          const activeTab = this.props.activeKey === this.props.keyNumber ? "active-tab" : null;
                          return (
                                  <div 
                                      className = {`${tabClassName} ${activeTab}`}
                                      onClick={()=>this.props.onClick(this.props.keyNumber)}
                                  >
                                      I am here
                                  </div>
                          );
                      }
                  }
                  
                  
                  export default Tab;
                  

                  标签文件...

                  import React, { Component } from 'react';
                  import Tab from './tab';
                  
                  class Tabs extends Component {
                  
                      constructor(props){
                          super(props);
                  
                          this.state = {
                              currentActiveKey: 0,
                              tabNumber: 2
                          };
                  
                          this.setActive = this.setActive.bind(this);
                          this.setTabNumber = this.setTabNumber.bind(this);
                      }
                  
                      setTabNumber(number){
                          this.setState({
                              tabNumber: number
                          });
                      }
                  
                      setActive (key){
                          this.setState({
                              currentActiveKey: key 
                          });
                      }
                  
                      render(){
                          let tabs = [];
                          for(let i = 0; i <= this.state.tabNumber; i++){
                              let tab = <Tab key={i} keyNumber={i} onClick={this.setActive} activeKey={this.state.currentActiveKey}/>;
                              tabs.push(tab);
                          }
                          return (
                              <div className="row">
                                  {tabs}
                              </div>
                          );
                      }
                  }
                  
                  
                  export default Tabs;
                  

                  您的索引文件...

                  import React from 'react';
                  import ReactDOM from 'react-dom';
                  import Tabs from './components/tabs';
                  
                  
                  ReactDOM.render(
                      <Tabs />
                    , document.querySelector('.container'));
                  

                  和css

                  .tab-bar {
                      margin: 10px 10px;
                      border: 1px solid grey;
                  }
                  
                  .active-tab {
                      border-top: 1px solid red;
                  }
                  

                  这是我想要改进的框架,因此将 tabNumber 增加到 4 以上会破坏 css。

                  【讨论】:

                    【解决方案13】:

                    这是我想出的代码:

                    import React, {Component} from "react";
                    import './header.css'
                    
                    export default class Header extends Component{
                        state = {
                            active : false
                        };
                    
                    
                        toggleMenuSwitch = () => {
                            this.setState((state)=>{
                                return{
                                    active: !state.active
                                }
                            })
                        };
                        render() {
                            //destructuring
                            const {active} = this.state;
                    
                            let className = 'toggle__sidebar';
                    
                            if(active){
                                className += ' active';
                            }
                    
                            return(
                                <header className="header">
                                    <div className="header__wrapper">
                                        <div className="header__cell header__cell--logo opened">
                                            <a href="#" className="logo">
                                                <img src="https://www.nrgcrm.olezzek.id.lv/images/logo.svg" alt=""/>
                                            </a>
                                            <a href="#" className={className}
                                               onClick={ this.toggleMenuSwitch }
                                               data-toggle="sidebar">
                                                <i></i>
                                            </a>
                                        </div>
                                        <div className="header__cell">
                    
                                        </div>
                                    </div>
                                </header>
                            );
                        };
                    };
                    

                    【讨论】:

                      【解决方案14】:

                      您可以简单地使用 event.target 访问接收到点击事件的元素 classList,然后使用 classList 对象上的切换方法来添加或删除预期的类

                      <div onClick={({target}) => target.classList.toggle('active')}>
                        ....
                        ....
                        ....
                      </div>
                      

                      相当的

                      <div onClick={e=> e.target.classList.toggle('active')}>
                        ....
                        ....
                        ....
                      </div>
                      

                      或者通过声明一个处理点击并做额外工作的函数

                      function handleClick(el){
                          .... Do more stuff
                          el.classList.toggle('active');
                      
                      }
                      <div onClick={({target})=> handleClick(target)}>
                        ....
                        ....
                        ....
                      </div>
                      

                      【讨论】:

                      • 欢迎来到 Stack Overflow!虽然您的回答可能会解决问题,但 including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。您可以编辑您的答案以添加解释并指出适用的限制和假设。 - From Review
                      【解决方案15】:

                      只是想添加我的方法。使用钩子和上下文提供程序。

                      Nav.js

                      function NavBar() {
                        const filterDispatch = useDispatchFilter()
                        const {filter} = useStateFilter()
                        const activeRef = useRef(null)
                        const completeRef = useRef(null)
                        const cancelRef = useRef(null)
                      
                        useEffect(() => {
                          let activeClass = '';
                          let completeClass = '';
                          let cancelClass = '';
                          if(filter === ACTIVE_ORDERS){
                            activeClass='is-active'
                          }else if ( filter === COMPLETE_ORDERS ){
                            completeClass='is-active'
                          }else if(filter === CANCEL_ORDERS ) {
                            cancelClass='is-active'
                          }
                          activeRef.current.className = activeClass
                          completeRef.current.className = completeClass
                          cancelRef.current.className = cancelClass
                        }, [filter])
                      
                        return (
                          <div className="tabs is-centered">
                            <ul>
                              <li ref={activeRef}>
                                <button
                                  className="button-base"
                                  onClick={() => filterDispatch({type: 'FILTER_ACTIVE'})}
                                >
                                  Active
                                </button>
                              </li>
                      
                              <li ref={completeRef}>
                                <button
                                  className="button-base"
                                  onClick={() => filterDispatch({type: 'FILTER_COMPLETE'})}
                                >
                                  Complete
                                </button>
                              </li>
                              <li ref={cancelRef}>
                                <button
                                  className={'button-base'}
                                  onClick={() => filterDispatch({type: 'FILTER_CANCEL'})}
                                >
                                  Cancel
                                </button>
                              </li>
                            </ul>
                          </div>
                        )
                      }
                      
                      export default NavBar
                      

                      filterContext.js

                      export const ACTIVE_ORDERS = [
                        "pending",
                        "assigned",
                        "pickup",
                        "warning",
                        "arrived",
                      ]
                      export const COMPLETE_ORDERS = ["complete"]
                      export const CANCEL_ORDERS = ["cancel"]
                      
                      const FilterStateContext = createContext()
                      const FilterDispatchContext = createContext()
                      
                      export const FilterProvider = ({ children }) => {
                        const [state, dispatch] = useReducer(FilterReducer, { filter: ACTIVE_ORDERS })
                        return (
                          <FilterStateContext.Provider value={state}>
                            <FilterDispatchContext.Provider value={dispatch}>
                              {children}
                            </FilterDispatchContext.Provider>
                          </FilterStateContext.Provider>
                        )
                      }
                      export const useStateFilter = () => {
                        const context = useContext(FilterStateContext)
                        if (context === undefined) {
                          throw new Error("place useStateMap within FilterProvider")
                        }
                        return context
                      }
                      export const useDispatchFilter = () => {
                        const context = useContext(FilterDispatchContext)
                        if (context === undefined) {
                          throw new Error("place useDispatchMap within FilterProvider")
                        }
                        return context
                      }
                      
                      
                      export const FilterReducer = (state, action) => {
                        switch (action.type) {
                          case "FILTER_ACTIVE":
                            return {
                              ...state,
                              filter: ACTIVE_ORDERS,
                            }
                          case "FILTER_COMPLETE":
                            return {
                              ...state,
                              filter: COMPLETE_ORDERS,
                            }
                          case "FILTER_CANCEL":
                            return {
                              ...state,
                              filter: CANCEL_ORDERS,
                            }
                        }
                        return state
                      }
                      

                      运行速度快,并且取代了 redux。

                      【讨论】:

                        【解决方案16】:
                        const aDiv = useRef(null);
                        
                        function app(){
                        const [isDark, setIsDark] = useState();
                        useEffect(()=>{
                        if(isDark){
                         aDiv.current.classList.add('dark-mode')
                        }else{
                         aDiv.current.classList.remove('dark-mode')
                        }
                        
                        },[isDark]}
                        return <div className = "app" ref = {aDiv}> </div>
                        

                        useRef 来标识元素以切换类,然后是布尔值 useState 来跟踪切换,如果为真,我们获取 ref 的当前类列表,然后添加一个类名,否则我们删除类名。 所有这些都发生在使用我们的 useState 作为依赖数组的 useEffect 中。

                        【讨论】:

                        • 虽然这段代码 sn-p 可以解决问题,但它没有解释为什么或如何回答这个问题。请include an explanation for your code,因为这确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
                        猜你喜欢
                        • 2018-05-18
                        • 2018-02-27
                        • 2018-02-10
                        • 1970-01-01
                        • 2023-02-12
                        • 1970-01-01
                        • 2020-10-30
                        • 1970-01-01
                        相关资源
                        最近更新 更多