Jak łączyć wiele obiektów w stylu wbudowanym?


214

W React możesz wyraźnie utworzyć obiekt i przypisać go jako styl wbudowany. to znaczy. wspomniane poniżej.

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

Jak mogę połączyć wiele obiektów i przypisać je razem?


Jak wyglądają te dwa obiekty?
Ryan,

Odpowiedzi:


399

Jeśli używasz React Native, możesz użyć notacji tablicowej:

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

Sprawdź mój szczegółowy post na blogu na ten temat.


41
Niestety nie możesz tego zrobić w zwykłym React.
YoTengoUnLCD

8
To powinna być zaakceptowana odpowiedź, jeśli używasz React-Native
calcazar

Możesz nieznacznie zmodyfikować istniejący styl wbudowany, dodając nazwy / wartości stylu. Na przykład<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
Gürol Canbek

W przypadku dwóch stylów statycznych wykonywanie StyleSheet.compose()poza funkcją renderowania może być bardziej wydajne. Stworzy nowy statyczny arkusz stylów, który zostanie przesłany przez most tylko raz. (Ta rada nie dotyczy stylów, które zmieniają się w czasie wykonywania lub które są wstawiane zamiast w
arkuszu stylów

282

Możesz użyć operatora rozprzestrzeniania:

 <button style={{...styles.panel.button,...styles.panel.backButton}}>Back</button

8
Pojawia się komunikat „Błąd składni: nieoczekiwany token” wskazujący na pierwszą kropkę w pierwszym operatorze rozkładania.
Izkata

@Izkata Czy robisz to w reakcji lub reakcji rodzimej, czy możesz opublikować swój fragment
kodu

React, to było coś w stylu<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata

I tak to zmieniłem, żeby użyć funkcji pomocniczej, tak <div style={LEGEND_STYLE.box_gen('#123456')}czy inaczej, więc dla mnie to nie jest wielka sprawa
Izkata

Działa to nawet wtedy, gdy obiekt ma tylko jedną parę klucz-wartość, mimo że operatory rozkładania powinny być poprawne tylko dla iterowalnych! Czy możesz mi wytłumaczyć dlaczego? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Tyler

47

Możesz to zrobić za pomocą Object.assign().

W twoim przykładzie zrobiłbyś:

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

To połączy te dwa style. Drugi styl zastąpi pierwszy, jeśli istnieją pasujące właściwości.

Jak zauważył Brandon, powinieneś użyć, Object.assign({}, divStyle, divStyle2)jeśli chcesz ponownie użyć divStylebez zastosowanej czcionkiSize.

Lubię to wykorzystywać do tworzenia komponentów o domyślnych właściwościach. Na przykład, oto mały komponent bezstanowy z domyślnym margin-right:

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

Możemy więc renderować coś takiego:

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

Co da nam wynik:

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

5
to rozwiązanie jest potencjalnie niewłaściwie wykorzystywane Object.assign()w sposób, który prowadziłby do niepożądanych konsekwencji. Zobacz odpowiedź tutaj, bardziej niezawodne rozwiązanie.
Brandon

1
Twoja odpowiedź pokazuje sposób niewłaściwego użycia Object.assign (). To może być przydatna informacja dla niektórych osób, ale nie dotyczy mojego przykładu. Ten przykład nie przechowuje wartości domyślnej w obiekcie, mutuje go, a następnie ponownie wykorzystuje zmutowany obiekt w innym miejscu.
qel

nie zgadzać się. Object.assign()w swojej odpowiedzi podasz dwa różne sposoby wykorzystania . pierwsze, w pierwszych kilku zdaniach, jest przykładem niewłaściwego użycia, które zidentyfikowałem (tj. jeśli OP codezrobiłby to, co doradzasz w pierwszym bloku, zmutowałby {divStyle}). drugi sposób - tzn. zawinięcie go w funkcję taką, jaką masz, zadziała, ale odpowiedź nie wyjaśnia, że ​​pracujesz nad Object.assign() niezmiennością „gotcha” wrt (chociaż osobiście uważam, że to trochę kłopotliwe jest napisanie niestandardowej funkcji bezstanowej dla każdego domyślnego komponentu).
Brandon

OK To prawda. Jeśli chciałby ponownie użyć divStyle bez zastosowania fontSize, najpierw potrzebowałby pustego obiektu. Zaktualizuję odpowiedź.
qel

Object.assign () jest zdecydowanie najwygodniejszym sposobem na osiągnięcie konkatenacji :)
aldobsom

29

W przeciwieństwie do React Native, nie możemy przekazać tablicy stylów w React, np

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

W React musimy utworzyć pojedynczy obiekt stylów przed przekazaniem go do właściwości stylu. Lubić:

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

  let enhancedStyle = {
    fontSize: '38px'
  }

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

Użyliśmy operatora ES6 Spread, aby połączyć dwa style. Możesz również użyć Object.assign () w tym samym celu.

Działa to również, jeśli nie musisz przechowywać swojego stylu w var

<Segment style={{...segmentStyle, ...{height:'100%'}}}>
    Your content
</Segment>

Nie możemy przekazać tablicy do stylu?
heisenberg

3
Aby dodać do ostatniego fragmentu kodu, {{... segmentStyle, wysokość: „100%”}} również będzie działał.
Luke Brandon Farrell

26

Object.assign()jest łatwym rozwiązaniem, ale użycie (obecnie) najwyższej odpowiedzi - choć jest w porządku do tworzenia elementów bezstanowych, spowoduje problemy w pożądanym celu PO polegającym na połączeniu dwóch stateobiektów.

Za pomocą dwóch argumentów Object.assign()faktycznie mutuje pierwszy obiekt w miejscu, wpływając na przyszłe wystąpienia.

Dawny:

Rozważ dwie możliwe konfiguracje stylu dla pudełka:

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

Dlatego chcemy, aby wszystkie nasze pola miały domyślne style „pól”, ale chcemy nadpisać niektóre innym kolorem:

// 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's blue.
<div style={styles.box}></div>

Po Object.assign()uruchomieniu obiekt „styles.box” zostaje na dobre zmieniony.

Rozwiązaniem jest przekazanie pustego obiektu Object.assign(). Robiąc to, mówisz metodzie, aby wytworzyć NOWY obiekt z obiektami, które przekazujesz. Tak jak:

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

To pojęcie obiektów mutujących w miejscu jest kluczowe dla React, a prawidłowe użycie Object.assign()jest naprawdę pomocne w korzystaniu z bibliotek takich jak Redux.


1
Twój przykład niewłaściwego użycia Object.assign nie jest prawidłową reprezentacją tego, w jaki sposób Object.assign jest używany w (obecnie) najważniejszej odpowiedzi.
qel

dzięki, wprowadzono zmiany w celu odzwierciedlenia, który aspekt jest (obecnie) niewłaściwy
Brandon

1
ładny kawałek kodu. Warunek Object.assign ({}, this.state.showStartOverBtn? {}: This.hidden, this.btnStyle)} również działa jak urok
steveinatorx

17

Notatka tablicowa to najlepszy sposób łączenia stylów w reakcji native.

To pokazuje, jak połączyć 2 obiekty Style,

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

pokazuje, jak połączyć obiekt i właściwość Style,

<Text style={[styles.base, {color: 'red'}]} >Test </Text>

Będzie to działać na każdej aplikacji natywnej reagującej.


2
Pytania dotyczą React, a nieReact Native
Dimitar Tsonev

Możesz użyć tego samego do React także
Sasindu Lakshitha

React nie obsługuje tablicy od samego początku, a teraz już nie działa.
witoong623

nie reaguj jeszcze wspieraj łącz styl w ten sposób.
zły kiwi

12

Możesz także łączyć klasy ze stylem wbudowanym w ten sposób:

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

8

W rzeczywistości istnieje formalny sposób łączenia i wygląda to tak:

<View style={[style01, style02]} />

Ale jest mały problem , jeśli jeden z nich jest przekazywany przez komponent nadrzędny i został utworzony przez połączenie formalne, mamy duży problem:

// The passing style02 from props: [parentStyle01, parentStyle02]

// Now:
<View style={[style01, [parentStyle01, parentStyle02]]} />

Ta ostatnia linia powoduje błąd interfejsu użytkownika, niestety React Native nie może poradzić sobie z głęboką tablicą wewnątrz tablicy. Więc tworzę moją funkcję pomocnika:

import { StyleSheet } from 'react-native';

const styleJoiner = (...arg) => StyleSheet.flatten(arg);

Używając mojego w styleJoinerdowolnym miejscu, możesz łączyć dowolny styl i łączyć style. nawet undefinedinne bezużyteczne typy nie powodują zepsucia stylizacji.


5

Przekonałem się, że to działa dla mnie najlepiej. Zastępuje zgodnie z oczekiwaniami.

return <View style={{...styles.local, ...styles.fromProps}} />

2

Dla tych, którzy szukają tego rozwiązania w React, jeśli chcesz używać operatora rozkładania wewnątrz stylu, powinieneś użyć: babel-plugin-transform-object-rest-spread.

Zainstaluj go za pomocą modułu npm i skonfiguruj .babelrc jako taki:

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

Następnie możesz użyć jak ...

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

Więcej informacji: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-spread/


2

Aby pójść dalej, możesz utworzyć funkcję pomocniczą podobną do nazw klas:

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

A następnie użyj go warunkowo w swoich komponentach:

<div style={

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

}>Hello World!</div>

0

Zasadniczo patrzę na to w niewłaściwy sposób. Z tego, co widzę, nie jest to pytanie specyficzne dla React, bardziej pytanie JavaScript, w jaki sposób połączyć razem dwa obiekty JavaScript (bez blokowania właściwości o podobnych nazwach).

W tej odpowiedzi StackOverflow wyjaśnia to. Jak mogę dynamicznie łączyć właściwości dwóch obiektów JavaScript?

W jQuery mogę użyć metody ext.


1
Samo scalanie obiektów nie wystarczy podczas pracy z obiektami zawierającymi style CSS. Istnieją właściwości skrótów, różne litery itp., Które powinny być obsługiwane we właściwej kolejności przez funkcję scalania. Szukam i nie znalazłem jeszcze biblioteki, która zapewnia taką funkcję.
sompylasar

Oto biblioteka, która dokonuje skrócenia właściwości: github.com/kapetan/css-shorthand-expand , ale nie jest to kompletne rozwiązanie.
sompylasar

0

Aby rozwinąć to, co powiedział @PythonIsGreat, tworzę globalną funkcję, która zrobi to za mnie:

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

To głęboko rozszerza obiekty na nowy obiekt i pozwala na zmienną liczbę obiektów jako parametrów. Pozwala to zrobić coś takiego:

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

var styles = {
  base:{
    //whatever
  },
  first:{
    //whatever
  },
  second:{
    //whatever
  }
}

Funkcja scalania zwykłego obiektu nie wystarcza podczas pracy z obiektami zawierającymi style CSS. Zobacz mój komentarz do powyższej odpowiedzi.
sompylasar


0

Sposoby stylizacji w linii:

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

3
React nie obsługuje tablicy od samego początku, a teraz już nie działa.
witoong623
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.