Jak dodać wiele klas do ReactJS Component


347

Jestem nowy w ReactJS i JSX i mam mały problem z poniższym kodem.

Próbuję dodać wiele klas do classNameatrybutu na każdym li:

<li key={index} className={activeClass, data.class, "main-class"}></li>

Mój komponent React to:

var AccountMainMenu = React.createClass({
  getInitialState: function() {
    return { focused: 0 };
  },

  clicked: function(index) {
    this.setState({ focused: index });
  },

  render: function() {
    var self = this;
    var accountMenuData = [
      {
        name: "My Account",
        icon: "icon-account"
      },
      {
        name: "Messages",
        icon: "icon-message"
      },
      {
        name: "Settings",
        icon: "icon-settings"
      }
    /*{
        name:"Help &amp; Support &nbsp; <span class='font-awesome icon-support'></span>(888) 664.6261",
        listClass:"no-mobile last help-support last"
      }*/
    ];

    return (
      <div className="acc-header-wrapper clearfix">
        <ul className="acc-btns-container">
          {accountMenuData.map(function(data, index) {
            var activeClass = "";

            if (self.state.focused == index) {
              activeClass = "active";
            }

            return (
              <li
                key={index}
                className={activeClass}
                onClick={self.clicked.bind(self, index)}
              >
                <a href="#" className={data.icon}>
                  {data.name}
                </a>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
});

ReactDOM.render(<AccountMainMenu />, document.getElementById("app-container"));

Znalazłem tutaj odpowiedź breif stackoverflow.com/a/36209517/4125588 , po prostu użyj JavaScript, aby dołączyć do tych klas, statycznych lub dynamicznych, z operatorem „+”, pamiętaj, aby wstawić „” przed klasami, z wyjątkiem pierwszej, jako rzeczywistą klasa w HTML powinna być jak „ab c”, również spacja między nimi.
Fadeoc Khaos


1
Dlaczego nie classNames={{foo: true, bar: true, baz: false}}i classNames={["foo", "bar"]}po prostu pracować ?
Peter V. Mørch

Odpowiedzi:


221

Używam nazw klas, gdy do podjęcia decyzji o użyciu (nie) klas potrzebna jest logika. Zbyt prosty przykład :

...
    var liClasses = classNames({
      'main-class': true,
      'activeClass': self.state.focused === index
    });

    return (<li className={liClasses}>{data.name}</li>);
...

To powiedziawszy, jeśli nie chcesz uwzględniać zależności, poniżej znajdziesz lepsze odpowiedzi.


189
Szkoda, że
musiałeś

4
@ user959690 To jest przykład. Ta biblioteka jest bardzo przyjemna, gdy często robisz te rzeczy i masz złożoną logikę, kiedy klasy muszą być stosowane, czy nie. Jeśli robisz coś prostego, skorzystaj z szablonów, ale każdy przypadek jest inny, a czytelnik powinien wybrać odpowiednie narzędzie do swojej pracy.
Jack

7
@ user959690 Warto zauważyć, że teraz jest on instalowany przez NPM podczas korzystania z pakietu Webpack , więc import classNames from 'classnames'należy go użyć w komponencie className={classNames(classes.myFirstClass, classes.mySecondClass)} .
Hooligancat

5
Nie trzeba używać biblioteki zewnętrznej, zobacz moją odpowiedź poniżej.
Huw Davies,

1
Biblioteka ma inne zalety: var btnClass = classNames({ btn: true, 'btn-pressed': this.state.isPressed, 'btn-over': !this.state.isPressed && this.state.isHovered }); return <button className={btnClass}>{this.props.label}</button>;
AmitJS94,

396

Używam ES6 literałów szablonów . Na przykład:

const error = this.state.valid ? '' : 'error'
const classes = `form-control round-lg ${error}`

A następnie po prostu renderuj:

<input className={classes} />

Wersja jednowarstwowa:

<input className={`form-control round-lg ${this.state.valid ? '' : 'error'}`} />

158
Również:<input className={`class1 ${class2}`}>
Cody Moniz

3
@unyo Prześlij swój komentarz jako odpowiedź, aby móc go zagłosować. Tak bardzo na to zasługuje. Szukałem 1 godziny na coś tak łatwego, a teraz uważam to za komentarz. Dziękuję Ci.
Souvik Ghosh,

To powoduje <input class=" form-control input-lg round-lg" />. Zwróć uwagę na dodatkowe miejsce na początku. To jest poprawne, ale brzydkie. Nawet zareaguj FAQ zaleca inny sposób lub użycie pakietu nazw klas
Nakedible

Nie mogę zrozumieć, dlaczego zaimportowałeś bibliotekę (jak w zaakceptowanej odpowiedzi), aby ustawić tylko niektóre klasy, które można ustawić za pomocą Vanilla JavaScript, który jest i tak bardziej wydajnym, czystszym i czytelniejszym rozwiązaniem.
Marcus Parsons,

2
To jest poprawna odpowiedź. Używanie do tego zależności, jak sugeruje to w „poprawnej” odpowiedzi, to przesada.
TheDarkIn1978

171

Po prostu użyj JavaScript.

<li className={[activeClass, data.klass, "main-class"].join(' ')} />

Jeśli chcesz dodać klucze i wartości oparte na klasach w obiekcie, możesz użyć:

function classNames(classes) {
  return Object.entries(classes)
    .filter(([key, value]) => value)
    .map(([key, value]) => key)
    .join(' ');
}

const classes = {
  'maybeClass': true,
  'otherClass': true,
  'probablyNotClass': false,
};

const myClassNames = classNames(classes);
// Output: "maybeClass otherClass"

<li className={myClassNames} />

Lub jeszcze prościej:

const isEnabled = true;
const isChecked = false;

<li className={[isEnabled && 'enabled', isChecked && 'checked']
  .filter(e => !!e)
  .join(' ')
} />
// Output:
// <li className={'enabled'} />

Oto linia, która zadziałała dla mnie:className={['terra-Table', medOrder.resource.status]}
Doug Wilhelm

1
@DougWilhelm Nie sądzę, że to działa. Niejawnie wywołuje toString i tworzy listę klas oddzieloną przecinkami. github.com/facebook/react/issues/3138
0xcaff

6
Dobry pomysł na wykorzystanie className={[listOfClasses].join(' ')}, działa dla mnie dzięki!
Ala Eddine JEBALI

98

Concat

Nie musisz być fantazyjny Używam modułów CSS i jest to łatwe

import style from '/css/style.css';

<div className={style.style1+ ' ' + style.style2} />

Spowoduje to:

<div class="src-client-css-pages-style1-selectionItem src-client-css-pages-style2">

Innymi słowy, oba style

Warunkowe

Łatwo byłoby użyć tego samego pomysłu z if

const class1 = doIHaveSomething ? style.style1 : 'backupClass';

<div className={class1 + ' ' + style.style2} />

1
To zadziałało dla mnie, wraz z nazwami „-”, tj .: <nav className = {styles.navbar + "” „+ styles ['navbar-default']}>
Flinkman

LOL, łamie mi głowę, a odpowiedź jest prosta konkat: D. Przy okazji ta praca również z modułem
ładującym

Problem polega na tym, że nie możesz mieć klas opcjonalnych (jeśli niezdefiniowana, to nie zostanie dodana), więc zależy to od tego, czy masz pewność, że twoja klasa nie jest pusta (nie opcjonalna). W przypadku opcjonalnego nie ma lepszego pomocnika niż klasy (). możemy użyć trójki z szablonami takimi jak ten className={suwak $ {className? `$ {className} : ''}}` `. Ale to dużo. [uwaga: „coś” + undefined = „coś niedostatecznie”. Dynamiczna konwersja Js.
Mohamed Allal

Jasne, że możesz, po prostu zadeklaruj zmienną powyżej i użyj jej warunkowo :)
Jamie Hutber

42

Można to osiągnąć za pomocą literałów szablonów ES6:

<input className={`class1 ${class2}`}>

1
to prawie dla mnie zadziałało. Po prostu musiałem interpolować klasę 1 i żadnych błędów, więc wygląda to tak <input className={`${class1} ${class2}`}>
Kingston Fortune,

35

Możesz utworzyć element o wielu nazwach klas, taki jak ten:

<li className="class1 class2 class3">foo</li>

Oczywiście możesz użyć łańcucha zawierającego nazwy klas i manipulować nim, aby zaktualizować nazwy klas elementu.

var myClassNammes = 'class1 class2 class3';
...
<li className={myClassNames}>foo</li>

1
Testowałeś to? Zrobiłem :)
kruk

Tak. Właściwie używam go dość często, ale właśnie zobaczyłem i poprawiłem literówkę. Oczywiście ciąg zawierający nazwy klas w pierwszym wierszu należy wykonać za pomocą "zamiast '. Przepraszam za to.
nightlyop

20

Oto jak możesz to zrobić za pomocą ES6:

className = {`
      text-right
      ${itemId === activeItemId ? 'active' : ''}
      ${anotherProperty === true ? 'class1' : 'class2'}
`}

Możesz wymienić wiele klas i warunków, a także możesz dołączyć klasy statyczne. Nie jest konieczne dodawanie dodatkowej biblioteki.

Powodzenia ;)


2
Powoduje to bardzo brzydki HTML, biorąc pod uwagę wszystkie dodatkowe białe znaki.
Nakedible

2
Nie trzeba tak pisać. To tylko przykład, który lepiej wyjaśnia rozwiązanie. I zawsze w produkcji masz wersję zminimalizowaną :)
Hristo Eftimov

18

Vanilla JS

Nie potrzebujesz zewnętrznych bibliotek - po prostu użyj ciągów szablonów ES6 :

<i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>

Vanilla JS NIE jest ES6. Ale podoba mi się twój przykład.
RyanNerd,

8
@RyanNerd Czy masz na myśli „ES6 nie jest waniliowy JS”? W każdym razie jest tak, ponieważ waniliowy js oznacza javascript bez żadnych ram. ES6 to nowsza wersja javascript. - stackoverflow.com/a/20435685/5111113
Huw Davies

Nie jest to zła odpowiedź, ale można ją znacznie poprawić. Na przykład wszyscy inni dodawali przykłady dotyczące stanów.
JGallardo

10

Może nazwy klas mogą ci pomóc.

var classNames = require('classnames');
classNames('foo', {'xx-test': true, bar: false}, {'ox-test': false}); // => 'foo xx-test'

1
Czy możesz uczynić ten przykład bardziej użytecznym?
JGallardo

9

Nie sądzę, że potrzebujemy zewnętrznego pakietu do dodawania wielu klas.

Ja osobiście korzystam

<li className={`li active`}>Stacy</li>

lub

<li className={`li ${this.state.isActive ? 'active' : ''}`}>Stacy<li>

drugi w przypadku, gdy musisz warunkowo dodać lub usunąć klasy.


1
spowoduje to dodanie tylko jednej klasy w jedną stronę.
TrickOrTreat

6

Dodając, możemy odfiltrować puste ciągi.

className={[
    'read-more-box',
    this.props.className,
    this.state.isExpanded ? 'open' : 'close',
].filter(x => !!x).join(' ')}

6

Możesz utworzyć element o wielu nazwach klas takich jak ten, wypróbowałem je w obie strony, działa dobrze ...

Jeśli importujesz css, możesz postępować w następujący sposób: Sposób 1:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={[styles.class1, styles.class2].join(' ')}>
        { 'text' }
      </div>
    );
  }
}

sposób 2:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={styles.class1 + ' ' + styles.class2}>
        { 'text' }
      </div>
    );
  }
}

**

Jeśli stosujesz css jako wewnętrzny:

const myStyle = {
  color: "#fff"
};

// React Element using Jsx
const myReactElement = (
  <h1 style={myStyle} className="myClassName myClassName1">
    Hello World!
  </h1>
);

ReactDOM.render(myReactElement, document.getElementById("app"));
.myClassName {
  background-color: #333;
  padding: 10px;
}
.myClassName1{
  border: 2px solid #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
<div id="app">
  
</div>


6

Możesz wykonać następujące czynności:

<li key={index} className={`${activeClass} ${data.class} main-class`}></li>

Krótkie i proste rozwiązanie, mam nadzieję, że to pomoże.



4

Późno na imprezę, ale po co używać strony trzeciej do tak prostego problemu?

Możesz to zrobić, jak wspomniał @Huw Davies - najlepszy sposób

1. <i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>
2. <i className={[styles['foo-bar-baz'], 'fa fa-user', 'fa-2x'].join(' ')}

Obie są dobre. Ale pisanie może stać się skomplikowane dla dużej aplikacji. Aby było to optymalne, robię to samo powyżej, ale umieszczam to w klasie pomocniczej

Korzystanie z mojej funkcji pomocnika pozwala mi oddzielić logikę do przyszłej edycji, a także daje mi wiele sposobów dodawania klas

classNames(styles['foo-bar-baz], 'fa fa-user', 'fa-2x')

lub

classNames([styles['foo-bar-baz], 'fa fa-user', 'fa-2x'])

To jest moja funkcja pomocnika poniżej. Umieściłem go w pliku helper.js, w którym trzymam wszystkie moje powszechne metody. Będąc tak prostą funkcją, uniknąłem korzystania z zewnętrznych programów, aby zachować kontrolę

export function classNames (classes) {
    if(classes && classes.constructor === Array) {
        return classes.join(' ')
    } else if(arguments[0] !== undefined) {
        return [...arguments].join(' ')
    }
    return ''
}

3

Możesz użyć tablic, a następnie połączyć je za pomocą spacji.

<li key={index} className={[activeClass, data.class, "main-class"].join(' ')}></li>

Spowoduje to:

<li key={index} class="activeClass data.class main-class"></li>

3

Wiem, że to późna odpowiedź, ale mam nadzieję, że to komuś pomoże.

Weź pod uwagę, że zdefiniowałeś następujące klasy w pliku css „ primary ”, „ font-i ”, „ font-xl

  • Pierwszym krokiem byłoby zaimportowanie pliku CSS.
  • Następnie

<h3 class = {` ${'primary'} ${'font-i'} font-xl`}> HELLO WORLD </h3>

zrobiłby lewę!

Aby uzyskać więcej informacji: https://www.youtube.com/watch?v=j5P9FHiBVNo&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=20



2

Korzystanie TodoTextInput.js przykład Facebooka

render() {
    return (
      <input className={
        classnames({
          edit: this.props.editing,
          'new-todo': this.props.newTodo
        })}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  } 

zastąpienie nazw klas zwykłym waniliowym kodem js będzie wyglądać następująco:

render() {
    return (
      <input
        className={`
          ${this.props.editing ? 'edit' : ''} ${this.props.newTodo ? 'new-todo' : ''}
        `}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  }

2

Jeśli nie masz ochoty importować innego modułu, ta funkcja działa jak classNamesmoduł.

function classNames(rules) {
    var classes = ''

    Object.keys(rules).forEach(item => {    
        if (rules[item])
            classes += (classes.length ? ' ' : '') + item
    })

    return classes
} 

Możesz użyć tego w następujący sposób:

render() {
    var classes = classNames({
        'storeInfoDiv': true,  
        'hover': this.state.isHovered == this.props.store.store_id
    })   

    return (
        <SomeComponent style={classes} />
    )
}

Po co używać zamknięć, jeśli możesz zrobić to samo z mapą lub zmniejszyć? function classNames(rules) { return Object.entries(rules) .reduce( (arr, [cls, flag]) => { if (flag) arr.push(cls); return arr }, [] ).join(" ") }
Евгений Савичев

1

To jest to co robię:

Składnik:

const Button = ({ className }) => (
  <div className={ className }> </div>
);

Składnik wywołujący:

<Button className = 'hashButton free anotherClass' />

1

Korzystam z React 16.6.3 i @Material UI 3.5.1 i mogę używać tablic w className jak className={[classes.tableCell, classes.capitalize]}

Tak więc w twoim przykładzie następujące byłyby podobne.

<li key={index} className={[activeClass, data.class, "main-class"]}></li>

To właśnie robiłem (choć nie ma MUI) i nie działa, dotyczy tylko pierwszej klasy - bez ostrzeżenia i narzekań.
Juan Lanus

1

Skorzystaj z https://www.npmjs.com/package/classnames

import classNames z 'classnames';

  1. Może korzystać z wielu klas za pomocą oddzielonych przecinków:

    <li className={classNames(classes.tableCellLabel, classes.tableCell)}>Total</li>
  2. Może używać wielu klas, używając przecinków oddzielonych warunkiem:

    <li className={classNames(classes.buttonArea, !nodes.length && classes.buttonAreaHidden)}>Hello World</li> 

Korzystanie z tablicy jako rekwizytów do classNames również będzie działać, ale ostrzega np

className={[classes.tableCellLabel, classes.tableCell]}


0

Używam pakietu rc-classnames .

// ES6
import c from 'rc-classnames';

// CommonJS
var c = require('rc-classnames');

<button className={c('button', {
  'button--disabled': isDisabled,
  'button--no-radius': !hasRadius
})} />

Możesz dodawać klasy w dowolnym formacie (Array, Object, Argument). Wszystkie prawdziwe wartości z tablic lub argumentów plus klucze w obiektach równychtrue scaleniu.

na przykład:

ReactClassNames('a', 'b', 'c') // => "a b c"
ReactClassNames({ 'a': true, 'b': false, c: 'true' }) // => "a c"
ReactClassNames(undefined, null, 'a', 0, 'b') // => "a b"

0

I bind classNamesdo modułu css zaimportowanego do komponentu.

import classNames from 'classnames'; 
import * as styles from './[STYLES PATH];
const cx = classNames.bind(styles); 

classnamesdaje możliwość deklarowania classNameelementu React w sposób deklaratywny.

dawny:

<div classNames={cx(styles.titleText)}> Lorem </div>

<div classNames={cx('float-left')}> Lorem </div> // global css declared without css modules
<div classNames={cx( (test === 0) ?
             styles.titleText : 
             styles.subTitleText)}>  Lorem </div> // conditionally assign classes

<div classNames={cx(styles.titleText, 'float-left')}> Lorem </div> //combine multiple classes

0

Zwykle używam tego w ten sposób: (w twoim przypadku)

    <li  key={index} className={
        "component " +
        `${activeClass? activeClass: " not-an-active-class "}` +
        `${data.class? " " + data.class : " no-data-class "}`
   } />

Jeśli chodzi o JSX i (zwykle) mamy trochę json ... niż go zapętlisz ... komponent . map , a także niektóre warunkowe, aby sprawdzić, czy istnieje właściwość json, aby wyświetlić nazwę klasy w zależności od wartości właściwości z JSON. W poniższym przykładzie component_color i component_dark_shade są właściwościami z component.map ()

   <div className={
        "component " +
        `${component_color? component_color: " no-color "}` +
        `${component_dark_shade? " " + component_dark_shade : " light "}`
   }/>

Wyjście: <div class="component no-color light" .... Lub: w <div class="component blue dark" ....zależności od wartości z mapy ...


0

Kiedy mam wiele różnych klas, uważam, że poniższe są przydatne.

Filtr usuwa dowolne nullwartości, a sprzężenie umieszcza wszystkie pozostałe wartości w ciągu oddzielonym spacjami.

const buttonClasses = [
    "Button", 
    disabled ? "disabled" : null,
    active ? "active" : null
].filter((class) => class).join(" ")

<button className={buttonClasses} onClick={onClick} disabled={disabled ? disabled : false}>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.