Làm thế nào để kết hợp nhiều đối tượng phong cách nội tuyến?


213

Trong React, bạn có thể tạo một đối tượng rõ ràng và gán nó theo kiểu nội tuyến. I E. đề cập dưới đây.

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

Làm thế nào tôi có thể kết hợp nhiều đối tượng và gán chúng lại với nhau?


Hai đối tượng trông như thế nào?
Ryan

Câu trả lời:


396

Nếu bạn đang sử dụng React Native, bạn có thể sử dụng ký hiệu mảng:

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

Kiểm tra bài viết chi tiết của tôi về điều này.


41
Đáng buồn thay, bạn không thể làm điều này trong React thường xuyên.
YoTengoUnLCD

8
Đây phải là câu trả lời được chấp nhận nếu bạn đang sử dụng React-Native
calcazar

Bạn có thể sửa đổi một chút kiểu nội tuyến hiện có bằng cách thêm tên / giá trị kiểu. Ví dụ:<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
Gürol Canbek

Đối với hai kiểu tĩnh, thực hiện StyleSheet.compose()bên ngoài chức năng kết xuất có thể hiệu quả hơn. Nó sẽ tạo ra một bản định kiểu tĩnh mới sẽ chỉ được gửi qua cầu một lần. (Lời khuyên này không áp dụng cho các kiểu thay đổi trong thời gian chạy hoặc là nội tuyến thay vì trong StyleSheet.)
joeytwiddle

282

Bạn có thể sử dụng toán tử trải rộng:

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

8
Tôi nhận được "Lỗi cú pháp: Mã thông báo bất ngờ", chỉ vào dấu chấm đầu tiên trong toán tử trải rộng đầu tiên.
Izkata

@Izkata Bạn đang làm điều này trong phản ứng hoặc phản ứng bản địa, bạn có thể đăng đoạn trích của mình không
Nath

Phản ứng lại, nó giống như<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata

Dù sao tôi cũng đã thay đổi nó để sử dụng chức năng của người trợ giúp <div style={LEGEND_STYLE.box_gen('#123456')}, vì vậy đó không phải là vấn đề lớn với tôi
Izkata

Điều này thậm chí hoạt động nếu đối tượng chỉ có một cặp khóa-giá trị, mặc dù các toán tử trải rộng chỉ được coi là hợp lệ cho các lần lặp! Bạn có thể giải thích lý do tại sao? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Khăn

47

Bạn có thể làm điều này với Object.assign().

Trong ví dụ của bạn, bạn sẽ làm:

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

Điều đó sẽ hợp nhất hai phong cách. Kiểu thứ hai sẽ thay thế kiểu thứ nhất nếu có các thuộc tính khớp.

Như Brandon đã lưu ý, bạn nên sử dụng Object.assign({}, divStyle, divStyle2)nếu bạn muốn sử dụng lại divStylemà không áp dụng fontSize cho nó.

Tôi thích sử dụng điều này để làm cho các thành phần với các thuộc tính mặc định. Ví dụ: đây là một thành phần không trạng thái với mặc định margin-right:

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

Vì vậy, chúng ta có thể kết xuất một cái gì đó như thế này:

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

Điều này sẽ cho chúng ta kết quả:

<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
giải pháp này có khả năng lạm dụng Object.assign()theo cách có thể dẫn đến một số hậu quả không mong muốn. Xem câu trả lời ở đây một giải pháp đáng tin cậy hơn.
Brandon

1
Câu trả lời của bạn thể hiện một cách để sử dụng sai Object.assign (). Đó có thể là thông tin hữu ích cho một số người, nhưng nó không áp dụng cho ví dụ của tôi. Ví dụ này không lưu trữ mặc định trong một đối tượng, làm biến đổi nó, sau đó sử dụng lại đối tượng bị đột biến ở một nơi khác.
qel

không đồng ý. bạn giải quyết hai cách sử dụng riêng biệt Object.assign()trong câu trả lời của bạn. câu đầu tiên, trong một vài câu đầu tiên, là một ví dụ về việc sử dụng sai mà tôi đã xác định (nghĩa là, nếu OP đã làm những gì bạn khuyên trong codekhối đầu tiên của mình , anh ấy / cô ấy sẽ biến đổi {divStyle}). cách thứ hai - tức là, bọc nó trong một chức năng như bạn có, sẽ hoạt động, nhưng câu trả lời không làm rõ rằng bạn đang làm việc Object.assign() với tính bất biến 'gotcha' thông thường (mặc dù cá nhân tôi nghĩ rằng nó hơi nhỏ cồng kềnh để viết một hàm không trạng thái tùy chỉnh cho mọi thành phần mặc định).
Brandon

Ồ được thôi. Đúng. Nếu anh ta muốn sử dụng lại divStyle mà không áp dụng fontSize thì trước tiên cần có đối tượng trống. Tôi sẽ cập nhật câu trả lời.
qel

Object.assign () cho đến nay là cách thuận tiện nhất để đạt được kết nối :)
aldobsom

29

Không giống như React Native, chúng ta không thể vượt qua một loạt các kiểu trong React, như

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

Trong React, chúng ta cần tạo một đối tượng duy nhất của các kiểu trước khi chuyển nó sang thuộc tính style. Giống:

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

  let enhancedStyle = {
    fontSize: '38px'
  }

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

Chúng tôi đã sử dụng toán tử lây lan ES6 để kết hợp hai kiểu. Bạn cũng có thể sử dụng Object.assign () cho cùng một mục đích.

Điều này cũng hoạt động nếu bạn không cần lưu trữ kiểu của mình trong một var

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

Chúng ta không thể vượt qua mảng để phong cách?
heisenberg

3
Chỉ cần thêm vào đoạn mã cuối cùng của bạn, {{... SegStyle, height: '100%'}} cũng sẽ hoạt động.
Luke Brandon Farrell

26

Object.assign()là một giải pháp dễ dàng, nhưng cách sử dụng câu trả lời hàng đầu (hiện tại) của nó - trong khi chỉ tốt khi tạo các thành phần không trạng thái, sẽ gây ra vấn đề cho mục tiêu mong muốn của OP là hợp nhất hai stateđối tượng.

Với hai đối số, Object.assign()sẽ thực sự làm thay đổi đối tượng đầu tiên tại chỗ, ảnh hưởng đến việc khởi tạo trong tương lai.

Ví dụ:

Xem xét hai cấu hình kiểu có thể cho một hộp:

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

Vì vậy, chúng tôi muốn tất cả các hộp của mình có kiểu 'hộp' mặc định, nhưng muốn ghi đè lên một số bằng một màu khác:

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

Khi Object.assign()thực thi, đối tượng 'Styles.box' được thay đổi cho tốt.

Giải pháp là truyền một đối tượng trống vào Object.assign(). Khi làm như vậy, bạn đang nói phương thức tạo ra một đối tượng MỚI với các đối tượng bạn vượt qua nó. Thích như vậy:

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

Khái niệm về các đối tượng đột biến tại chỗ rất quan trọng đối với React và việc sử dụng đúng cách Object.assign()thực sự hữu ích cho việc sử dụng các thư viện như Redux.


1
Ví dụ của bạn về cách sử dụng sai Object.assign không phải là một đại diện hợp lệ về cách Object.assign đang được sử dụng trong câu trả lời hàng đầu (hiện tại).
qel

cảm ơn, đã chỉnh sửa để phản ánh khía cạnh nào (hiện tại) là lạm dụng
Brandon

1
đoạn mã đẹp ngay đó. Object.assign (? {}, This.state.showStartOverBtn {}: this.hidden, this.btnStyle)} điều kiện cũng làm việc như một nét duyên dáng
steveinatorx

17

Array notaion là cách tốt nhất để kết hợp các kiểu trong phản ứng gốc.

Điều này cho thấy cách kết hợp 2 đối tượng Style,

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

Điều này cho thấy cách kết hợp đối tượng Style và thuộc tính,

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

Điều này sẽ làm việc trên bất kỳ ứng dụng gốc phản ứng.


2
Các câu hỏi dành cho React, không phảiReact Native
Dimitar Tsonev

Bạn cũng có thể sử dụng tương tự cho React
Sasindu Lakshitha

React không hỗ trợ mảng từ đầu và bây giờ nó không hoạt động nữa.
witoong623

Phản ứng chưa hỗ trợ kết hợp phong cách như thế này.
kiwi tức giận

12

Bạn cũng có thể kết hợp các lớp với kiểu dáng nội tuyến như thế này:

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

8

Trên thực tế, có một cách chính thức để kết hợp và nó giống như dưới đây:

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

Nhưng, có một vấn đề nhỏ , nếu một trong số chúng được thông qua bởi thành phần cha mẹ và nó được tạo ra bởi một cách chính thức kết hợp, chúng ta có một vấn đề lớn:

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

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

Và dòng cuối cùng này gây ra lỗi UI, chắc chắn, React Native không thể xử lý một mảng sâu bên trong một mảng. Vì vậy, tôi tạo chức năng trợ giúp của mình:

import { StyleSheet } from 'react-native';

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

Bằng cách sử dụng styleJoinerbất cứ nơi nào tôi có thể kết hợp bất kỳ loại phong cách và kết hợp phong cách. thậm chí undefinedhoặc các loại vô dụng khác không gây ra phá vỡ kiểu dáng.


5

Tôi đã thấy rằng điều này làm việc tốt nhất cho tôi. Nó ghi đè như mong đợi.

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

2

Đối với những người tìm kiếm giải pháp này trong React, Nếu bạn muốn sử dụng toán tử lây lan bên trong kiểu, bạn nên sử dụng: babel-plugin-Transform-object-rest-lây lan.

Cài đặt nó bằng mô-đun npm và định cấu hình .babelrc của bạn như sau:

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

Sau đó, bạn có thể sử dụng như ...

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

Thông tin thêm: https://babeljs.io/docs/en/babel-plugin-transform-object-rest-s lây /


2

Để thực hiện điều này hơn nữa, bạn có thể tạo một hàm trợ giúp giống như tên lớp :

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

Và sau đó sử dụng nó một cách có điều kiện trong các thành phần của bạn:

<div style={

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

}>Hello World!</div>

0

Vì vậy, về cơ bản tôi đang nhìn điều này theo cách sai. Từ những gì tôi thấy, đây không phải là một câu hỏi cụ thể về React, hơn nữa là một câu hỏi JavaScript về cách tôi kết hợp hai đối tượng JavaScript với nhau (mà không ghi đè các thuộc tính có tên tương tự).

Trong câu trả lời StackOverflow này, nó giải thích nó. Làm cách nào tôi có thể hợp nhất các thuộc tính của hai đối tượng JavaScript một cách linh hoạt?

Trong jQuery tôi có thể sử dụng phương thức mở rộng.


1
Chỉ hợp nhất các đối tượng là không đủ khi làm việc với các đối tượng có chứa kiểu CSS. Có các thuộc tính tốc ký, vỏ chữ cái khác nhau, vv cần được xử lý theo đúng thứ tự của hàm hợp nhất. Tôi đang tìm và chưa tìm thấy một thư viện cung cấp chức năng như vậy.
sompylasar

Đây là một thư viện thực hiện mở rộng thuộc tính tốc ký: github.com/kapetan/css-shorthand-Exand , nhưng đây không phải là một giải pháp hoàn chỉnh.
sompylasar

0

Để mở rộng những gì @PythonIsGreat đã nói, tôi tạo một hàm toàn cầu sẽ làm điều đó cho tôi:

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

Điều này mở rộng sâu sắc các đối tượng thành một đối tượng mới và cho phép một số lượng đối tượng khác nhau làm tham số. Điều này cho phép bạn làm một cái gì đó như thế này:

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

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

Hàm hợp nhất đối tượng đơn giản là không đủ khi làm việc với các đối tượng có chứa kiểu CSS. Xem bình luận của tôi để trả lời ở trên.
sompylasar


0

Những cách tạo kiểu nội tuyến:

<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 không hỗ trợ mảng từ đầu và bây giờ nó không hoạt động nữa.
witoong623
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.