如何合并多个内联样式对象?


213

在React中,您可以清楚地创建一个对象并将其分配为嵌入式样式。即。如以下所说的。

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

如何合并多个对象并将它们分配在一起?


这两个对象是什么样的?
Ryan

Answers:


396

如果您使用的是React Native,则可以使用数组符号:

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

查看有关此内容的详细博客文章


41
遗憾的是,您无法在常规React中做到这一点。
YoTengoUnLCD '17

8
如果您使用的是React-Native,这应该是可接受的答案
calcazar

您可以通过添加样式名称/值来稍微修改现有的嵌入式样式。例如,<View style={this.state.error == false ? styles.base : [styles.base, {backgroundColor: 'red'}]} />
GürolCanbek

对于两种静态样式,StyleSheet.compose()在渲染功能之外执行操作可能会更有效率。它将生成一个新的静态样式表,该样式表将仅通过网桥发送一次。(此建议不适用于在运行时更改的样式,或者不适用于StyleSheet的内联样式。)
joeytwiddle19年

282

您可以使用点差运算符:

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

8
我得到“语法错误:意外的令牌”,指向第一个扩展运算符中的第一个点。
Izkata '16

@Izkata您是在响应还是在本地响应中执行此操作,您能否发布您的摘录
2016年

反应,就像<div style={{ ...LEGEND_STYLE.box_base, ...{ 'background': '#123456' } }} />
Izkata '16

无论如何,我还是像使用辅助功能一样对其进行了更改<div style={LEGEND_STYLE.box_gen('#123456')},所以对我来说没什么大不了
Izkata

即使对象仅具有一个键值对,即使散布运算符仅对可迭代对象有效,这也可以使用!你能解释为什么吗?developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
泰勒(Tyler)

47

您可以使用Object.assign()

在您的示例中,您将执行以下操作:

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

这将合并两种样式。如果有匹配的属性,则第二种样式将替换第一种样式。

正如Brandon所指出的,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>

5
该解决方案可能Object.assign()会以某种方式滥用,从而导致某些不良后果。在此处查看答案,这是更可靠的解决方案。
布兰登

1
您的答案演示了一种滥用Object.assign()的方法。对于某些人来说,这可能是有用的信息,但不适用于我的示例。此示例未将默认值存储在对象中,对其进行了变异,然后在其他地方重新使用了变异的对象。
qel

不同意。您Object.assign()在答案中提出了两种单独的使用方式。首先,在前几句话中,是我发现的误用示例(即,如果OP在您的第一个code步骤中做了您建议的操作,他/她将变异{divStyle})。第二种方法-即将其包装在您拥有的函数中将起作用,但是答案并不清楚,您正在解决 Object.assign() “通用”陷阱的不变性(尽管我个人认为这有点为每个默认组件编写自定义无状态函数很麻烦)。
布兰登

哦好的。确实如此。如果他想在不应用fontSize的情况下重用divStyle,则需要首先使用空对象。我将更新答案。
qel

Object.assign()是迄今为止实现串联的最便捷方法:)
aldobsom

29

与React Native不同,我们无法在React中传递样式数组,例如

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

在React中,我们需要先创建样式的单个对象,然后再将其传递给style属性。喜欢:

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>

我们不能将数组传递给样式吗?
heisenberg

3
只需添加到您的最后一个片段,{{... segmentStyle,height:'100%'}}也可以使用。
卢克·布兰登·法雷尔

26

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

一旦Object.assign()执行,“ styles.box”对象将永久更改。

解决方案是将一个空对象传递给Object.assign()。这样,您要告诉该方法使用传递的对象来生成一个NEW对象。像这样:

// 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之类的库。


1
您关于如何滥用Object.assign的示例不是有效地表示(当前)最佳答案中Object.assign的使用方式。
qel

谢谢,进行了修改以反映(当前)滥用的方面
Brandon

1
不错的一段代码。Object.assign({},this.state.showStartOverBtn?{}:this.hidden,this.btnStyle)}条件句也像符咒一样起作用
steveinatorx

17

数组概念是在React Native中组合样式的最佳方法。

这显示了如何组合2个Style对象,

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

这说明了如何结合样式对象和属性,

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

这将适用于任何React本机应用程序。


2
问题是React,不是React Native
贝尔巴托夫Tsonev

您也可以将其用于React
Sasindu Lakshitha

React从一开始就不支持数组,现在不再起作用。
witoong623

反应还不支持像这样的组合风格。
愤怒的猕猴桃


8

实际上,有一种正式的组合方式,如下所示:

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

但是,这是一个小问题,如果其中一个由父组件传递并且是通过组合的正式方式创建的,那么我们会遇到一个大问题:

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

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

最后一行导致出现UI错误,当然,React Native无法处理数组内部的深层数组。因此,我创建了我的辅助函数:

import { StyleSheet } from 'react-native';

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

通过styleJoiner在任何地方使用我,您可以组合任何类型的样式并组合样式。甚至undefined其他无用的类型也不会破坏样式。



2

对于在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/


2

为了使这一步更进一步,您可以创建一个类似于类名的辅助函数:

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的问题,更多的是JavaScript问题,如何将两个JavaScript对象组合在一起(不破坏相似名称的属性)。

在这个StackOverflow答案中进行了解释。 如何动态合并两个JavaScript对象的属性?

在jQuery中,我可以使用extend方法。


1
使用包含CSS样式的对象时,仅合并对象是不够的。有速记属性,不同的字母大小写等,应通过合并功能按正确的顺序处理。我正在寻找但尚未找到提供此类功能的图书馆。
sompylasar 2015年

这是一个进行简写属性扩展的库:github.com/kapetan/css-shorthand-expand,但这不是一个完整的解决方案。
sompylasar 2015年

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

当使用包含CSS样式的对象时,单纯的对象合并功能是不够的。请参阅我对以上答案的评论。
sompylasar 2015年


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>

3
React从一开始就不支持数组,现在不再起作用。
witoong623
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.