Próbuję dowiedzieć się, jak przełączyć aktywną klasę, onClick
aby zmienić właściwości CSS.
Podjąłem wiele podejść i przeczytałem wiele odpowiedzi TAK. Korzystanie z jquery byłoby stosunkowo proste, jednak nie mogę wymyślić, jak to zrobić za pomocą reakcji. Mój kod jest poniżej. Czy ktoś może doradzić, jak mam to zrobić?
Czy można to zrobić bez tworzenia nowego komponentu dla każdego elementu?
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
peter flanagan
źródło
źródło
active
do każdego elementu po kliknięciu. Chcę tylko jednego elementu, aby mieć aktywną klasęonClick
Wolałbym używać operatora "&&" w instrukcji wbudowanej if. Moim zdaniem w ten sposób zapewnia czystszą bazę kodu.
Generalnie możesz robić coś takiego
render(){ return( <div> <button className={this.state.active && 'active'} onClick={ () => this.setState({active: !this.state.active}) }>Click me</button> </div> ) }
Pamiętaj tylko, że funkcja strzałki jest funkcją ES6 i pamiętaj, aby ustawić wartość 'this.state.active' w konstruktorze klasy () {}
this.state = { active: false }
lub jeśli chcesz wstrzyknąć css w JSX, możesz to zrobić w ten sposób
<button style={this.state.active && style.button} >button</button>
i możesz zadeklarować zmienną json stylu
const style = { button: { background:'red' } }
pamiętaj o używaniu camelCase w arkuszach stylów JSX.
źródło
Twój addActiveClass musi wiedzieć, co zostało kliknięte. Coś takiego mogłoby zadziałać (zauważ, że dodałem informacje, które elementy div są aktywne jako tablica stanu, i że onClick przekazuje teraz informacje, które kliknięto jako parametr, po którym stan jest odpowiednio aktualizowany - z pewnością są sprytniejsze sposoby zrób to, ale masz pomysł).
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> ); } }
źródło
Możesz to również zrobić za pomocą haczyków .
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> ); }
źródło
używając Reacta możesz dodać toggle class do dowolnego id / elementu, spróbuj
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; }
nazwa_pliku.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> ) } ......
źródło
className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
React ma koncepcję stanu komponentów, więc jeśli chcesz to zmienić, zrób
setState
:constructor(props) { super(props); this.addActiveClass= this.addActiveClass.bind(this); this.state = { isActive: false } } addActiveClass() { this.setState({ isActive: true }) }
W swoim komponencie użyj
this.state.isActive
do renderowania tego, czego potrzebujesz.Staje się to bardziej skomplikowane, gdy chcesz ustawić stan w komponencie nr 1 i użyć go w komponencie nr 2. Po prostu przyjrzyj się bliżej jednokierunkowemu przepływowi danych i prawdopodobnie zmniejszeniu, które pomoże Ci sobie z tym poradzić.
źródło
state
ale to nadal nie wyjaśnia, jak zaktualizować nazwę klasy po kliknięciu elementu<div className={this.state.isActive ? 'active' : ''}>
. Chodzi o renderowanie warunkowe, ale nadal opiera się na stanie.active
nazwę klasyItem
komponentu. Następnie umieścisz go 3 razy i zasadniczo będziesz miał 3 elementy, z których każdy ma swój własnyisActive
stan. Czy to masz na myśli?Item
komponent, czy jest na to sposób?Powyższe odpowiedzi będą działać, ale na wypadek, gdybyś chciał innego podejścia, wypróbuj nazwę klasy: https://github.com/JedWatson/classnames
źródło
Dobra próbka pomogłaby lepiej zrozumieć rzeczy:
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; }
Kod reakcji
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"));
źródło
możesz dodać klasę przełączania lub stan przełączania po kliknięciu
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> } }
źródło
Dzięki @cssko za udzielenie poprawnej odpowiedzi, ale jeśli spróbujesz tego sam, zorientujesz się, że to nie działa. @Matei Radu zasugerował, ale został odrzucony przez @cssko, więc kod pozostaje nie do uruchomienia (wyświetli się błąd „Nie można odczytać powiązania właściwości z niezdefiniowanej”). Poniżej znajduje się działająca poprawna odpowiedź:
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>
źródło
Niedawno zacząłem uczyć się Reacta i chciałem zbudować kartę, aby zobaczyć, jak daleko zaszła moja wiedza. Natknąłem się na to i postanowiłem wdrożyć coś bez redukcji. Wydaje mi się, że odpowiedzi nie odzwierciedlają tego, co OP chce osiągnąć. Chce tylko jednego aktywnego składnika, ale odpowiedzi tutaj spowodują, że wszystkie składniki będą aktywne. Dałem temu szansę.
Poniżej znajduje się plik karty
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;
Plik tabs ...
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;
twój plik indeksu ...
import React from 'react'; import ReactDOM from 'react-dom'; import Tabs from './components/tabs'; ReactDOM.render( <Tabs /> , document.querySelector('.container'));
i css
.tab-bar { margin: 10px 10px; border: 1px solid grey; } .active-tab { border-top: 1px solid red; }
To jest szkielet czegoś, co chcę ulepszyć, więc zwiększenie tabNumber powyżej 4 zepsuje css.
źródło
Oto kod, który wymyśliłem:
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> ); }; };
źródło
React ma koncepcję stanu komponentów, więc jeśli chcesz to przełączyć, użyj setState:
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;
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;
źródło
Chciałem tylko dodać moje podejście. Korzystanie z punktów zaczepienia i dostawcy kontekstu.
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 }
Działa szybko i zastępuje redux.
źródło