Bagaimana cara menggabungkan beberapa objek gaya inline?

214

Di Bereaksi, Anda dapat dengan jelas membuat objek dan menetapkannya sebagai gaya sebaris. yaitu. disebutkan di bawah.

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

Bagaimana saya bisa menggabungkan beberapa objek dan menetapkannya bersama?

PythonIsGreat
sumber
Seperti apa rupa kedua benda itu?
Ryan

Jawaban:

399

Jika Anda menggunakan React Native, Anda dapat menggunakan notasi array:

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

Lihat posting blog saya yang terperinci tentang ini.

Nick
sumber
41
Sayangnya Anda tidak dapat melakukan ini secara Bereaksi biasa.
YoTengoUnLCD
8
Ini harus menjadi jawaban yang diterima jika Anda menggunakan React-Native
calcazar
Anda dapat sedikit mengubah gaya inline yang ada dengan menambahkan nama / nilai gaya. Misalnya,<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
Gürol Canbek
Untuk dua gaya statis, melakukan di StyleSheet.compose()luar fungsi render mungkin lebih efisien. Ini akan menghasilkan stylesheet statis baru yang hanya akan dikirim melalui jembatan sekali. (Saran ini tidak berlaku untuk gaya yang berubah saat runtime, atau yang sebaris bukan dalam StyleSheet.)
joeytwiddle
282

Anda dapat menggunakan operator spread:

 <button style={{...styles.panel.button,...styles.panel.backButton}}>Back</button
Nath
sumber
8
Saya mendapatkan "Kesalahan sintaks: Token tak terduga", menunjuk titik pertama di operator spread pertama.
Izkata
@Izkata Apakah Anda melakukan ini sebagai reaksi atau reaksi asli, dapatkah Anda memposting cuplikan Anda
Nath
Bereaksi, itu seperti<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata
Saya tetap mengubahnya untuk menggunakan fungsi pembantu seperti <div style={LEGEND_STYLE.box_gen('#123456')}, jadi itu bukan masalah besar bagi saya
Izkata
Ini bahkan berfungsi jika objek hanya memiliki satu pasangan nilai kunci, meskipun operator spread hanya valid untuk iterables! Bisakah Anda jelaskan mengapa? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Tyler
47

Anda dapat melakukannya dengan Object.assign().

Dalam contoh Anda, Anda akan melakukan:

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

Itu akan menggabungkan dua gaya. Gaya kedua akan menggantikan yang pertama jika ada properti yang cocok.

Seperti dicatat Brandon, Anda harus menggunakan Object.assign({}, divStyle, divStyle2)jika Anda ingin menggunakan kembali divStyletanpa fontSize diterapkan untuk itu.

Saya suka menggunakan ini untuk membuat komponen dengan properti default. Sebagai contoh, inilah komponen stateless kecil dengan default margin-right:

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

Jadi kita dapat membuat sesuatu seperti ini:

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

Yang akan memberi kita hasilnya:

<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>
Qel
sumber
5
solusi ini berpotensi disalahgunakan Object.assign()dengan cara yang akan mengarah pada beberapa konsekuensi yang tidak diinginkan. Lihat jawabannya di sini solusi yang lebih andal.
Brandon
1
Jawaban Anda menunjukkan cara untuk menyalahgunakan Object.assign (). Itu mungkin informasi yang berguna bagi sebagian orang, tetapi itu tidak berlaku untuk contoh saya. Contoh ini tidak menyimpan default di objek, memutasikannya, lalu menggunakan kembali objek bermutasi di tempat lain.
qel
tidak setuju. Anda membahas dua cara berbeda dalam menggunakan Object.assign()jawaban Anda. yang pertama, dalam beberapa kalimat pertama, adalah contoh penyalahgunaan yang saya identifikasi (yaitu, jika OP melakukan apa yang Anda sarankan di codeblok pertama Anda , dia akan bermutasi {divStyle}). cara kedua - yaitu, membungkusnya dalam fungsi seperti yang Anda miliki, akan berhasil, tetapi jawabannya tidak menjelaskan bahwa Anda sedang bekerja di sekitar Object.assign() immutabilitas wrt 'gotcha' yang umum (meskipun secara pribadi saya pikir itu sedikit rumit untuk menulis fungsi stateless khusus untuk setiap komponen default).
Brandon
Oh oke. Itu benar. Jika dia ingin menggunakan kembali divStyle tanpa menerapkan fontSize itu perlu objek kosong terlebih dahulu. Saya akan memperbarui jawabannya.
qel
Object.assign () sejauh ini merupakan cara yang paling nyaman untuk mencapai
rangkuman
29

Tidak seperti Bereaksi Asli, kami tidak dapat meneruskan larik gaya di Bereaksi

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

Dalam Bereaksi, kita perlu membuat objek tunggal gaya sebelum meneruskannya ke properti gaya. Suka:

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

  let enhancedStyle = {
    fontSize: '38px'
  }

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

Kami telah menggunakan operator ES6 Spread untuk menggabungkan dua gaya. Anda juga bisa menggunakan Object.assign () juga untuk tujuan yang sama.

Ini juga berfungsi jika Anda tidak perlu menyimpan gaya Anda dalam var

<Segment style={{...segmentStyle, ...{height:'100%'}}}>
    Your content
</Segment>
pokhrel achyut
sumber
Kami tidak dapat meneruskan larik ke gaya?
heisenberg
3
Untuk menambah cuplikan terakhir Anda, {{... segmentStyle, height: '100%'}} juga akan berfungsi.
Luke Brandon Farrell
26

Object.assign()adalah solusi yang mudah, tetapi (saat ini) jawaban atas penggunaannya - walaupun baik untuk membuat komponen stateless, akan menyebabkan masalah bagi tujuan OP yang diinginkan untuk menggabungkan duastate objek.

Dengan dua argumen, Object.assign()sebenarnya akan bermutasi objek pertama di tempat, mempengaruhi instantiations masa depan.

Ex:

Pertimbangkan dua kemungkinan konfigurasi gaya untuk sebuah kotak:

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

Jadi kami ingin semua kotak kami memiliki gaya 'kotak' default, tetapi ingin menimpa beberapa dengan warna yang berbeda:

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

Setelah Object.assign()dieksekusi, objek 'styles.box' diubah untuk selamanya.

Solusinya adalah dengan mengirimkan objek kosong ke Object.assign(). Dengan demikian, Anda memberi tahu metode untuk menghasilkan objek BARU dengan objek yang Anda lewati. Seperti itu:

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

Gagasan objek bermutasi di tempat sangat penting untuk Bereaksi, dan penggunaan yang tepat Object.assign()sangat membantu untuk menggunakan perpustakaan seperti Redux.

Brandon
sumber
1
Contoh Anda tentang cara menyalahgunakan Object.assign bukan representasi yang valid tentang bagaimana Object.assign digunakan dalam jawaban teratas (saat ini).
qel
terima kasih, melakukan pengeditan untuk mencerminkan aspek mana yang (saat ini) merupakan penyalahgunaan
Brandon
1
sepotong kode yang bagus di sana. Object.assign ({}, this.state.showStartOverBtn? {}: This.hidden, this.btnStyle)} kondisi juga berfungsi seperti pesona
steveinatorx
17

Array notaion adalah cara terbaik untuk menggabungkan gaya dalam reaksi asli.

Ini menunjukkan cara menggabungkan 2 objek Style,

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

ini menunjukkan cara menggabungkan objek Style dan properti,

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

Ini akan bekerja pada aplikasi asli apa pun yang bereaksi.

Sasindu Lakshitha
sumber
2
Pertanyaannya adalah untuk React, bukanReact Native
Dimitar Tsonev
Anda dapat menggunakan yang sama untuk Bereaksi juga
Sasindu Lakshitha
Bereaksi tidak mendukung array dari awal dan sekarang tidak berfungsi lagi.
witoong623
Reaksi belum mendukung gaya menggabungkan seperti ini.
Kiwi
12

Anda juga dapat menggabungkan kelas dengan gaya inline seperti ini:

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

Sebenarnya, ada cara formal untuk menggabungkan dan seperti di bawah ini:

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

Tapi, ada masalah kecil , jika salah satunya dilewatkan oleh komponen induk dan itu dibuat dengan cara formal gabungan kita punya masalah besar:

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

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

Dan baris terakhir ini menyebabkan bug UI, bermuka masam, React Native tidak dapat menangani array yang dalam di dalam array. Jadi saya membuat fungsi pembantu saya:

import { StyleSheet } from 'react-native';

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

Dengan menggunakan saya di styleJoinermana saja Anda dapat menggabungkan semua jenis gaya dan menggabungkan gaya. bahkan undefinedatau tipe tidak berguna lainnya tidak menyebabkan penataan yang rusak.

Amerika
sumber
5

Saya telah menemukan bahwa ini bekerja paling baik untuk saya. Itu menimpa seperti yang diharapkan.

return <View style={{...styles.local, ...styles.fromProps}} />
Adrian Bartholomew
sumber
2

Untuk mereka yang mencari solusi ini di Bereaksi, Jika Anda ingin menggunakan operator dalam gaya, Anda harus menggunakan: babel-plugin-transform-objek-rest-spread.

Instal dengan modul npm dan konfigurasikan .brcrc Anda seperti itu:

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

Maka Anda dapat menggunakan seperti ...

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

Info lebih lanjut: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-spread/

Phoenix
sumber
2

Untuk mengambil yang ini lebih jauh, Anda bisa membuat fungsi pembantu seperti classnames :

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

Dan kemudian gunakan kondisional dalam komponen Anda:

<div style={

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

}>Hello World!</div>
streletss
sumber
0

Jadi pada dasarnya saya melihat ini dengan cara yang salah. Dari apa yang saya lihat, ini bukan pertanyaan spesifik Bereaksi, lebih merupakan pertanyaan JavaScript tentang bagaimana cara menggabungkan dua objek JavaScript bersama-sama (tanpa clobbering properti dengan nama yang sama).

Dalam jawaban StackOverflow ini menjelaskannya. Bagaimana saya bisa menggabungkan properti dua objek JavaScript secara dinamis?

Di jQuery saya bisa menggunakan metode extended.

PythonIsGreat
sumber
1
Hanya menggabungkan objek tidak cukup ketika bekerja dengan objek yang berisi gaya CSS. Ada properti singkatan, casing surat yang berbeda dll yang harus ditangani dalam urutan yang benar oleh fungsi penggabungan. Saya mencari dan belum menemukan perpustakaan yang menyediakan fungsi seperti itu.
sompylasar
Berikut adalah perpustakaan yang melakukan ekspansi properti: github.com/kapetan/css-shorthand-expand , tetapi ini bukan solusi lengkap.
sompylasar
0

Untuk Perluas apa yang dikatakan @PythonIsGreat, saya membuat fungsi global yang akan melakukannya untuk saya:

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

Ini sangat memperluas objek menjadi objek baru dan memungkinkan sejumlah variabel objek sebagai parameter. Ini memungkinkan Anda melakukan sesuatu seperti ini:

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

var styles = {
  base:{
    //whatever
  },
  first:{
    //whatever
  },
  second:{
    //whatever
  }
}
timthez
sumber
Fungsi penggabungan objek biasa tidak cukup saat bekerja dengan objek yang berisi gaya CSS. Lihat komentar saya untuk jawaban di atas.
sompylasar
0

Cara penataan inline:

<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>
dia
sumber
3
Bereaksi tidak mendukung array dari awal dan sekarang tidak berfungsi lagi.
witoong623