【问题标题】:How to add style - like margin - to react component?如何添加样式 - 如边距 - 以反应组件?
【发布时间】:2018-09-24 07:24:36
【问题描述】:

所以,期待我构建的两个简单组件:

import {Input} from 'semantic-ui-react';
import {Select} from 'semantic-ui-react';

const CategoriesDropdown = ({categories, onCategorySelected, selectedCategory}) => {
    const handleChange = (e, {value})=>{
        onCategorySelected(value);
    };
    return (
        <Select placeholder="Select category" search options={categories} onChange={handleChange} value={selectedCategory} />
    );
};

const IdentifiersInput = ({identifiers, onIdentifiersChanged}) => {
    return (
        <Input placeholder="Enter identifiers..." value={identifiers} onChange={onIdentifiersChanged}/>
    );
};

到目前为止没有什么特别的。

但是现在,我正在构建另一个组件,在 flexbox 行中显示这两个组件:

        <Box>
            <CategoriesDropdown categories={categories} selectedCategory={selectedCategoryId}
                           onCategorySelected={this.selectCategory}/>
            <IdentifiersInput identifiers={identifiers} onIdentifiersChanged={this.changeIdentifiers}/>
        </Box>

不幸的是,它们都紧挨着显示,中间没有任何边距。

通常,我会在第二个元素中添加一个margin-left 样式,但是因为它是一个 React 组件,所以这不起作用。使用style={{marginLeft: '20px'}} 效果不佳,因为IdentifiersInput 组件不使用它。
我知道我可以通过这样做来修复它:&lt;Input style={style} ...IdentifiersInput 组件内。
然而,这似乎是实现这一目标的一种非常乏味的方式。基本上,我必须将它添加到我正在编写的每个组件中。
我显然必须在这里遗漏一些东西。我应该如何将这样的布局 CSS 属性应用于 React 组件?

【问题讨论】:

  • &lt;Input {...this.props} /&gt;?
  • 当然,我仍然需要在 every single 组件中做一些事情。此外,它不会与现有值合并,例如如果组件已经指定了样式或类名。
  • 您是否尝试将 css 添加到您的输入中而不是您的组件中?
  • 我为什么要这样做?反应组件不应该是可重用吗?没有正当理由总是在 IdentifiersInput 上留有左边距。在那种特定情况下,它恰好需要一个。在另一种情况下,它可能出现在 CategoriesDropdown 之前,而可能需要右边距。
  • 什么保证金?你不能在你的情况下使用 flexbox 吗?

标签: javascript css reactjs


【解决方案1】:

我想我明白了。

1) 将 CSS 直接应用于 React 组件不起作用——我可以确认。

2) 将 props 向下传递给低级元素是乏味的、已确认但可行的。

通知hasMargin道具:

<Box>
  <CategoriesDropdown
    categories={categories}
    selectedCategory={selectedCategoryId}
    onCategorySelected={this.selectCategory}
  />
  <IdentifiersInput
    identifiers={identifiers}
    onIdentifiersChanged={this.changeIdentifiers}
    hasMargin
  />
</Box>

可能的输入:

const IdentifiersInput = ({identifiers, onIdentifiersChanged, className, hasMargin }) => {
  return (
    <Input
      className={className}
      placeholder="Enter identifiers..."
      value={identifiers}
      onChange={onIdentifiersChanged}
      style={hasMargin ? ({ marginLeft: '0.8rem' }) : ({})}
    />
  );
};

注意:我不喜欢样式,因为我喜欢添加一个额外的类,因为可以通过媒体查询来调整类:

const IdentifiersInput = ({identifiers, onIdentifiersChanged, className, hasMargin }) => {
  const inputPosition = hasMargin ? `${className} margin-sm` : className
  return (
    <Input
      className={inputPosition}
      placeholder="Enter identifiers..."
      value={identifiers}
      onChange={onIdentifiersChanged}
    />
  );
};

如果您发现inputPosition 过于冗长,如上图所示:

className={hasMargin ? `${className} margin-sm` : className}

3)您可以使用分隔组件来完成它,神圣但快速有效

<Box>
  <CategoriesDropdown
    categories={categories}
    selectedCategory={selectedCategoryId}
    onCategorySelected={this.selectCategory}
  />
  <div className="divider" />
  <IdentifiersInput
    identifiers={identifiers}
    onIdentifiersChanged={this.changeIdentifiers}
  />
</Box>

如果需要,您可以在任何断点处使用媒体查询和控制填充。

4) CSS 伪元素或伪类,到目前为止,我在答案中没有看到任何提及它们。

通常,当你有一个随机的 DOM 元素集合时,你可以计算出一种使用 CSS 将它们调整到正确位置的方法。可用的伪类列表位于该 MDN 链接中。老实说,只看它们并推理潜在的组合很有帮助。

我当前的问题是我不知道&lt;Box /&gt; 中的内容,除了它可能有一个带有display: flex; 的div。如果我们要做的就是这样,并且 div 被称为&lt;div className="Box"&gt;,也许像这样的一些 CSS 会修复它:

.Box {
  display: flex;
}

.Box:first-child {
  margin-right: 0.8rem;
}

这就是为什么准确了解周围元素将是或可能是什么以及附近有哪些 CSS 类/ID 非常重要的原因。我们基本上是在尝试挂钩并正确识别 Box 中的左孩子并在其右侧添加边距,或者以右孩子为目标并在其左侧添加边距(或根据所有内容,同时定位并拆分额外的两者都有边距)。

记住还有::before::after。欢迎您发挥创意,找到涉及position:relativeposition: absolute 且不添加任何标记的解决方案。

我现在就这样留下我的答案,因为我认为要么你已经考虑过伪选择器,要么你很快就会找到有用的东西:)

那个或分隔线实际上是相当可行的。您可以使用媒体查询的事实使您不必担心组件的未来管理或可伸缩性。我不会对&lt;div style={{}} /&gt;说同样的话。

【讨论】:

  • 感谢分隔线和伪类的想法。我没有考虑过它们,它实际上可能解决了我在“布局 CSS”方面遇到的问题。
  • 太好了,祝你好运。我最近在一个联系人表单中使用了一个分隔器,其中一行有两个输入,其余的有一个。没什么好抱怨的。我的意见是最重要的事情是确保您考虑所有断点,尤其是移动的flex-direction: column,当select 可能被堆叠时,集中在input 的顶部。
【解决方案2】:

由于您的组件专门用于另一个单个组件,因此将包装器不关心的任何道具传递给被包装的组件是一个好习惯。否则,您将失去使用原始 &lt;Input&gt;component 的 api 的能力,包括将样式传递给它:

const IdentifiersInput = ({identifiers, onIdentifiersChanged, ...props}) = (
    <Input 
        {...props}
        placeholder="Enter identifiers..." 
        value={identifiers} 
        onChange={onIdentifiersChanged}
    />
);

在某些有效的情况下,您明确希望阻止用户能够将道具传递给包装的组件,但在我看来这不是其中之一。

我显然必须在这里遗漏一些东西。我应该如何申请 这样的布局 CSS 属性到 React 组件?

你没有错过什么。 React 组件没有通用的样式设置方式,因为它不是 DOM 元素。它可以有一个非常复杂和嵌套的 DOM 表示或根本没有表示。所以在某些时候你作为组件的设计者必须决定应该在哪里应用样式、id 和类名。在您的情况下,将这些道具向下传递并让&lt;Input&gt;&lt;Select&gt;component 决定一样简单。我觉得这很优雅,而不是乏味。

【讨论】:

  • 我觉得这很乏味,因为我必须重复代码 , ...props{...props} 以及任何样式和类名一次又一次地合并。我来自 Angular,其中每个组件都是一个 Web 组件,它本质上是可样式化的。 很优雅...
【解决方案3】:

我看到了几种方法,但我看到的最简单的方法是将 className 传递给 IdentifiersInput,如下所示:

<IdentifiersInput className="marginLeft" identifiers={identifiers} onIdentifiersChanged={this.changeIdentifiers}/>

在 IdentifiersInput 中,我只需将该类设置为输入:

const IdentifiersInput = ({identifiers, onIdentifiersChanged, className}) => {
return (
    <Input className={className} placeholder="Enter identifiers..." value={identifiers} onChange={onIdentifiersChanged}/>
);
};

语义 UI 的 Input 元素可以接收一个 className 属性。 然后,我将只使用 CSS 或 SCSS 将样式添加到该特定类。在这种情况下,您想要的边距。

【讨论】:

  • 感谢您的回答。我知道我可以做到这一点,但是这个解决方案类似于{...props} 的建议:1. 我必须在每个单独的组件中实现这个,2. 我必须添加额外的代码,以防我的组件已经添加了其他类名。
猜你喜欢
  • 1970-01-01
  • 2021-06-17
  • 2019-02-08
  • 2017-05-21
  • 2022-06-19
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 1970-01-01
相关资源
最近更新 更多