Как добавить несколько классов в компонент ReactJS?


349

Я новичок в ReactJS и JSX, и у меня возникла небольшая проблема с кодом ниже.

Я пытаюсь добавить несколько классов к classNameатрибуту на каждом li:

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

Мой компонент React:

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"));

Я нашел краткий ответ здесь stackoverflow.com/a/36209517/4125588 , просто используйте JavaScript, чтобы объединить эти классы, статические или динамические, с оператором «+», не забудьте вставить «» перед классами, кроме первого, в качестве реального класс в HTML должен быть похож на 'ab c', а также пробел между ними.
Фадеок Хаос


1
Почему не classNames={{foo: true, bar: true, baz: false}}и classNames={["foo", "bar"]}просто работать ?
Петр В. Мёрч

Ответы:


221

Я использую имена классов, когда существует достаточное количество логики, необходимой для определения (не) использования классов. Чрезмерно простой пример :

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

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

Тем не менее, если вы не хотите включать зависимость, то есть лучшие ответы ниже.


191
Очень жаль, что вам пришлось ввести библиотеку
имён

4
@ user959690 Это пример. Эта библиотека очень хороша, когда вы много делаете, и у вас есть сложная логика, когда нужно применять классы или нет. Если вы делаете что-то простое, то обязательно используйте шаблоны, но каждый случай индивидуален, и читатель должен выбрать правильный инструмент для своей работы.
Джек,

7
@ user959690 Стоит отметить, что теперь он устанавливается NPM при использовании Webpack , поэтому import classNames from 'classnames'для использования в компоненте className={classNames(classes.myFirstClass, classes.mySecondClass)} .
Hooligancat

5
Нет необходимости использовать внешнюю библиотеку, см. Мой ответ ниже.
Хью Дэвис,

1
Библиотека имеет другие преимущества: 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

Я использую ES6 шаблонные литералы . Например:

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

А затем просто сделать это:

<input className={classes} />

Однолинейная версия:

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

158
Также:<input className={`class1 ${class2}`}>
Коди Мониз

3
@unyo Пожалуйста, оставьте свой комментарий в качестве ответа, чтобы я мог проголосовать. Это так много заслуживает. Я искал 1 час для чего-то столь же легкого, как это, и теперь я нахожу это похороненным в качестве комментария. Спасибо.
Сувик Гош

Это приводит к <input class=" form-control input-lg round-lg" />. Обратите внимание на дополнительное место в начале. Это действительно, но безобразно. Даже в ответах на часто задаваемые вопросы рекомендуется другой способ или использование пакета classnames: reactjs.org/docs/faq-styling.html
Nakedible

Я не могу понять, почему вы импортируете библиотеку (как в принятом ответе), чтобы просто установить некоторые классы, которые можно установить с помощью Vanilla JavaScript, который в любом случае является более эффективным, чистым и читаемым решением.
Маркус Парсонс

2
Это правильный ответ. Использование зависимости для этого, как предлагается в «правильном» ответе, излишне.
TheDarkIn1978

171

Просто используйте JavaScript.

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

Если вы хотите добавить ключи и значения на основе классов в объект, вы можете использовать следующее:

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} />

Или даже проще:

const isEnabled = true;
const isChecked = false;

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

Вот линия, которая работала для меня:className={['terra-Table', medOrder.resource.status]}
Дуг Вильгельм

1
@DougWilhelm Я не думаю, что это работает. Он неявно вызывает toString и создает список классов через запятую. github.com/facebook/react/issues/3138
0xcaff

6
Хорошая идея использовать className={[listOfClasses].join(' ')}это работает для меня, спасибо!
Ала Эддин ДЖЕБАЛИ

98

Concat

Не нужно фантазировать Я использую модули CSS, и это легко

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

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

Это приведет к:

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

Другими словами, оба стиля

Conditionals

Было бы легко использовать ту же идею с if

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

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

1
Это сработало для меня, наряду с именами '-', то есть: <nav className = {styles.navbar + "" + styles ['navbar-default']}>
Flinkman

LOL, я ломаю голову, и ответ простой конкат: D. Кстати, эта работа также работает с модулем CSS Loader
GusDeCooL,

Проблема в том, что у вас не может быть необязательных классов (если они не определены, то они не будут добавлены), поэтому все зависит от того, уверены ли вы, что ваш класс не нулевой (не необязательный). В случае необязательного, не лучше, чем помощник, как классы (). мы можем использовать троичную форму с такими шаблонами, как этот className={слайдер $ {className? `$ {className} : ''}}` `. Но это много. [примечание: «что-то» + undefined = «что-то недоопределено». Js динамическое преобразование.
Мохаммед Аллал

Конечно, вы можете просто объявить переменную выше и использовать ее условно :)
Jamie Hutber

43

Это может быть достигнуто с помощью литералов шаблона ES6:

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

1
это почти сработало для меня, мне просто нужно было интерполировать и class1, и ошибок больше не было, так что это выглядит так <input className={`${class1} ${class2}`}>
Kingston Fortune

35

Вы можете создать элемент с несколькими именами классов, например так:

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

Естественно, вы можете использовать строку, содержащую имена классов, и манипулировать этой строкой для обновления имен классов элемента.

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

1
Вы проверяли это? Я сделал :)
ворон

Да, я сделал. На самом деле, я использую его довольно часто, но только что увидел и исправил опечатку. Конечно, строка, содержащая имена классов в первой строке, должна быть сделана с использованием "вместо '. Извини за это.
nightlyop

20

Вот как вы можете сделать это с ES6:

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

Вы можете перечислить несколько классов и условий, а также вы можете включить статические классы. Нет необходимости добавлять дополнительную библиотеку.

Удачи ;)


2
Это приводит к очень уродливому HTML, учитывая все лишние пробелы.
Nakedible

2
Не надо так писать. Это всего лишь пример, который лучше объясняет решение. И всегда в производстве у вас есть уменьшенная версия :)
Христо Ефтимов

18

Ваниль JS

Нет необходимости во внешних библиотеках - просто используйте строки шаблона ES6 :

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

Vanilla JS - это не ES6. Но мне нравится твой пример.
RyanNerd

8
@RyanNerd Вы имеете в виду "ES6 не ванильный JS"? Во всяком случае, это так, потому что vanilla JS означает Javascript без каких-либо рамок. ES6 - более новая версия javascript. - stackoverflow.com/a/20435685/5111113
Хью Дэвис

Не неправильный ответ, но мог бы быть значительно улучшен. Например, все остальные добавили примеры о состояниях.
JGallardo

10

Может быть, имена классов могут помочь вам.

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

1
Можете ли вы сделать этот пример более полезным?
Джаллардо,

9

Я не думаю, что нам нужно использовать внешний пакет для добавления нескольких классов.

Я лично пользуюсь

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

или

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

второй на случай, если вам нужно добавить или удалить классы условно.


1
это добавит только один класс в любом случае.
TrickOrTreat

7

Вы можете сделать следующее:

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

Краткое и простое решение, надеюсь, это поможет.


ИМО это лучший ответ! :)
simhumileco

6

Просто добавив, мы можем отфильтровать пустые строки.

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

6

Вы можете создать элемент с несколькими именами классов, как это, я пробовал оба способа, он работает нормально ...

Если вы импортируете какой-либо CSS, то вы можете следовать следующим образом: Путь 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>
    );
  }
}

способ 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>
    );
  }
}

**

Если вы применяете CSS как внутренний:

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>


5

Это можно сделать с помощью https://www.npmjs.com/package/clsx :

https://www.npmjs.com/package/clsx

Сначала установите его:

npm install --save clsx

Затем импортируйте его в файл компонента:

import clsx from  'clsx';

Затем используйте импортированную функцию в вашем компоненте:

<div className={ clsx(classes.class1, classes.class2)}>

4

Опоздал на вечеринку, но зачем использовать третью сторону для такой простой задачи?

Вы можете сделать это, как упоминал @Huw Davies - лучший способ

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(' ')}

Оба хорошие. Но написание может стать сложным для большого приложения. Чтобы сделать его оптимальным, я делаю то же самое, но помещаю его в класс помощников.

Использование моей вспомогательной функции, приведенной ниже, позволяет мне отделить логику для будущего редактирования, а также дает мне несколько способов добавления классов

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

или

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

Это моя вспомогательная функция ниже. Я положил его в helper.js, где я храню все свои обычные методы. Будучи такой простой функцией, я избегал использования сторонней организации для сохранения контроля

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

3

Вы можете использовать массивы, а затем присоединиться к ним, используя пробел.

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

Это приведет к:

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

3

Я знаю, что это поздний ответ, но я надеюсь, что это поможет кому-то.

Предположим, что вы определили следующие классы в CSS-файле « primary », « font-i », « font-xl »

  • Первым шагом будет импорт файла CSS.
  • затем

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

сделал бы трюк!

Для получения дополнительной информации: https://www.youtube.com/watch?v=j5P9FHiBVNo&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=20



2

Используя пример Facebook TodoTextInput.js

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} />
    )
  } 

замена имен классов на простой ванильный js-код будет выглядеть так:

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

Если вы не хотите импортировать другой модуль, эта функция работает как classNamesмодуль.

function classNames(rules) {
    var classes = ''

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

    return classes
} 

Вы можете использовать это так:

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

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

Зачем использовать замыкания, если вы можете сделать то же самое с картой или уменьшить? function classNames(rules) { return Object.entries(rules) .reduce( (arr, [cls, flag]) => { if (flag) arr.push(cls); return arr }, [] ).join(" ") }
Евгений Савичев

1

Это то, чем я занимаюсь:

Составная часть:

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

Компонент вызова:

<Button className = 'hashButton free anotherClass' />

1

Я использую React 16.6.3 и @Material UI 3.5.1, и могу использовать массивы в className, как className={[classes.tableCell, classes.capitalize]}

Так что в вашем примере следующее будет похоже.

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

Это то, что я делал (хотя и не MUI) и не работает, применяется только первый класс - без предупреждения или жалоб.
Хуан Ланус

1

Используйте https://www.npmjs.com/package/classnames

импортировать classNames из 'classnames';

  1. Можно использовать несколько классов, используя разделенные комы:

    <li className={classNames(classes.tableCellLabel, classes.tableCell)}>Total</li>
  2. Можно использовать несколько классов, используя запятые, разделенные условием:

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

Использование массива в качестве реквизита для classNames также будет работать, но выдает предупреждение, например

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


0

Я использую пакет 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
})} />

Вы можете добавлять классы в любом формате (Array, Object, Argument). Все истинные значения из массивов или аргументов плюс ключи в объектах, которые равны, чтобы trueобъединиться вместе.

например:

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

Я bind classNamesв модуль CSS импортирован в компонент.

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

classnamesдает возможность декларировать classNameэлемент React декларативным способом.

например:

<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

Я обычно использую это так: (в вашем случае)

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

Когда дело доходит до JSX и (обычно) у нас есть некоторые json ... чем вы зацикливаете это ... компонент . map , плюс некоторые условные выражения, чтобы проверить, существует ли свойство json для отображения имени класса в зависимости от значения свойства из JSON. В приведенном ниже примере component_color и component_dark_shade являются свойствами из component.map ()

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

Вывод: <div class="component no-color light" .... или: в <div class="component blue dark" ....зависимости от значений из карты ...


0

Когда у меня много разных классов, я обнаружил, что полезно следующее.

Фильтр удаляет любое из nullзначений, а объединение помещает все оставшиеся значения в строку, разделенную пробелом.

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

<button className={buttonClasses} onClick={onClick} disabled={disabled ? disabled : false}>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.