Как объединить несколько встроенных объектов стиля?

124

В React вы можете четко создать объект и назначить его как встроенный стиль. i.e.., упомянутых ниже.

var divStyle = {
  color: 'white',
  backgroundImage: 'url(' + imgUrl + ')',
  WebkitTransition: 'all', // note the capital 'W' here
  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};

var divStyle2 = {fontSize: '18px'};

React.render(<div style={divStyle}>Hello World!</div>, mountNode);

Как объединить несколько объектов и назначить их вместе?

  • 0
    Как выглядят эти два объекта?
  • 0
    хм, это одна из причин, по которой я думаю, что стили должны быть оставлены в реакции?
Показать ещё 1 комментарий
Теги:

12 ответов

279

Если вы используете React Native, вы можете использовать нотацию массива:

<View style={[styles.base, styles.background]} />

Подробнее см. docs.

  • 18
    К сожалению, вы не можете сделать это в обычном React.
  • 0
    работает хорошо спасибо
Показать ещё 7 комментариев
213

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

 <button style={{...styles.panel.button,...styles.panel.backButton}}>Back</button
  • 8
    Это должно быть принято как правильный ответ!
  • 5
    Я получаю «Синтаксическая ошибка: неожиданный токен», указывающий на первую точку в первом операторе спреда.
Показать ещё 5 комментариев
36

Вы можете сделать это с помощью Object.assign().

В вашем примере вы бы сделали:

ReactDOM.render(
    <div style={Object.assign(divStyle, divStyle2)}>
        Hello World!
    </div>,
    mountNode
);

Это объединит два стиля. Второй стиль заменит первый, если есть соответствующие свойства.

Как отметил Брэндон, вы должны использовать Object.assign({}, divStyle, divStyle2), если вы хотите повторно использовать divStyle без применения fontSize к нему.

Мне нравится использовать это для создания компонентов со свойствами по умолчанию. Например, здесь небольшой компонент без состояния с по умолчанию margin-right:

const DivWithDefaults = ({ style, children, ...otherProps }) =>
    <div style={Object.assign({ marginRight: "1.5em" }, style)} {...otherProps}>
        {children}
    </div>;

Итак, мы можем сделать что-то вроде этого:

<DivWithDefaults>
    Some text.
</DivWithDefaults>
<DivWithDefaults className="someClass" style={{ width: "50%" }}>
    Some more text.
</DivWithDefaults>
<DivWithDefaults id="someID" style={{ marginRight: "10px", height: "20px"}}>
    Even more text.
</DivWithDefaults>

Что даст нам результат:

<div style="margin-right:1.5em;">Some text.</div>
<div style="margin-right:1.5em;width50%;" class="someClass">Some more text.</div>
<div style="margin-right:10px;height:20px;" id="someID">Even more text.</div>
  • 4
    это решение потенциально неправильно использует Object.assign() таким образом, что это может привести к нежелательным последствиям. Смотрите ответ здесь, более надежное решение.
  • 1
    Ваш ответ демонстрирует способ неправильного использования Object.assign (). Это может быть полезной информацией для некоторых людей, но это не относится к моему примеру. Этот пример не хранит значение по умолчанию в объекте, изменяет его, а затем повторно использует измененный объект где-то еще.
Показать ещё 2 комментария
19

Object.assign() является простым решением, но ( в настоящее время) топ ответ использование его - в то время как раз отлично для изготовления компонентов без гражданства, вызовет проблемы для OP желаемой цели слияния двух state объектов.

С двумя аргументами Object.assign() фактически мутирует первый объект на месте, влияя на будущие экземпляры.

Пример:

Рассмотрим две возможные конфигурации стилей для коробки:

var styles =  {
  box: {backgroundColor: 'yellow', height: '100px', width: '200px'},
  boxA: {backgroundColor: 'blue'},
};

Поэтому мы хотим, чтобы все наши блоки имели стили "по умолчанию", но хотим перезаписать их другим цветом:

// this will be yellow
<div style={styles.box}></div>

// this will be blue
<div style={Object.assign(styles.box, styles.boxA)}></div>

// this SHOULD be yellow, but it blue.
<div style={styles.box}></div>

Как только Object.assign() выполняется, объект 'styles.box' изменяется навсегда.

Решением является передача пустого объекта в Object.assign(). При этом вы говорите методу для создания нового объекта с объектами, которые вы передаете ему. Вот так:

// this will be yellow
<div style={styles.box}></div>

// this will be blue
<div style={Object.assign({}, styles.box, styles.boxA)}></div>

// a beautiful yellow
<div style={styles.box}></div>

Это понятие объектов, мутирующих на месте, является критическим для React, и правильное использование Object.assign() действительно полезно для использования таких библиотек, как Redux.

  • 0
    Ваш пример неправильного использования Object.assign не является верным представлением о том, как Object.assign используется в (в настоящее время) верхнем ответе.
  • 0
    спасибо, внес изменения, чтобы отразить, какой аспект (в настоящее время) используется не по назначению
Показать ещё 1 комментарий
16

В отличие от React Native, мы не можем передать массив стилей в React, например

<View style={[style1, style2]} />

В React нам нужно создать отдельный объект стилей перед передачей его в свойство стиля. Подобно:

const Header = (props) => {
  let baseStyle = {
    color: 'red',
  }

  let enhancedStyle = {
    fontSize: '38px'
  }

  return(
    <h1 style={{...baseStyle, ...enhancedStyle}}>{props.title}</h1>
  );
}

Мы использовали оператор ES6 Spread для объединения двух стилей. Вы также можете использовать Object.assign() для той же цели.

Это также работает, если вам не нужно хранить свой стиль в var

<Segment style={{...segmentStyle, ...{height:'100%'}}}>
    Your content
</Segment>
  • 0
    Мы не можем передать массив в стиль?
11

Вы также можете комбинировать классы со встроенным стилем так:

<View style={[className, {paddingTop: 25}]}>
  <Text>Some Text</Text>
</View>
0

Способы встроенного моделирования:

<View style={[styles.red, {fontSize: 25}]}>
  <Text>Hello World</Text>
</View>

<View style={[styles.red, styles.blue]}>
  <Text>Hello World</Text>
</View>

  <View style={{fontSize:10,marginTop:10}}>
  <Text>Hello World</Text>
</View>
0

Чтобы пойти еще дальше, вы можете создать вспомогательную функцию classnames -like:

const styleRules = (...rules) => {
  return rules.filter(Boolean).reduce((result, rule) => {
    return { ...result, ...rule };
  }, {});
};

А затем используйте его условно в ваших компонентах:

<div style={

  styleRules(
    divStyle,
    (window.innerWidth >= 768) && divStyleMd,
    (window.innerWidth < 768) && divStyleSm
  )

}>Hello World!</div>
0

Для тех, кто ищет это решение в React, если вы хотите использовать оператор распространения внутри стиля, вы должны использовать: babel-plugin-transform-object-rest-spread.

Установите его с помощью модуля npm и настройте ваш.babelrc следующим образом:

{
  "presets": ["env", "react"],
  "plugins": ["transform-object-rest-spread"]
}

Тогда вы можете использовать как...

const sizing = { width: 200, height: 200 }
 <div
   className="dragon-avatar-image-background"
   style={{ backgroundColor: blue, ...sizing }}
  />

Дополнительная информация: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-spread/

0

Я построил для этого модуль, если вы хотите добавить стили на основе условия например:

multipleStyles(styles.icon, { [styles.iconRed]: true })

https://www.npmjs.com/package/react-native-multiple-styles

0

Чтобы развернуть то, что сказал @PythonIsGreat, я создаю глобальную функцию, которая сделает это для меня:

var css = function(){
    var args = $.merge([true, {}], Array.prototype.splice.call(arguments, 0));
    return $.extend.apply(null, args);
}

Это глубоко расширяет объекты в новый объект и допускает переменное число объектов в качестве параметров. Это позволяет сделать что-то вроде этого:

return(
<div style={css(styles.base, styles.first, styles.second,...)} ></div>
);

var styles = {
  base:{
    //whatever
  },
  first:{
    //whatever
  },
  second:{
    //whatever
  }
}
  • 0
    Одной функции слияния простых объектов недостаточно при работе с объектами, которые содержат стили CSS. Смотрите мой комментарий к ответу выше.
0

Так что в основном я смотрю на это не так. Из того, что я вижу, это не конкретный вопрос React, а скорее вопрос JavaScript в том, как объединить два объекта JavaScript вместе (без сбивания аналогично названных свойств).

В этом ответе StackOverflow это объясняется. Как я могу объединить свойства двух объектов JavaScript динамически?

В jQuery я могу использовать метод extend.

  • 1
    Простого объединения объектов недостаточно при работе с объектами, которые содержат стили CSS. Существуют сокращенные свойства, различные регистры букв и т. Д., Которые должны обрабатываться в правильном порядке с помощью функции объединения. Я ищу и еще не нашел библиотеку, которая обеспечивает такую функцию.
  • 0
    Вот библиотека, которая сокращает свойства: github.com/kapetan/css-shorthand-expand , но это не полное решение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню