如何为 React 组件设计样式

作者选择了 Creative Commons以作为 Write for Donations计划的一部分获得捐赠。

介绍

在本教程中,您将学习三种不同的方式来设计 React组件:简单的 Cascading Style Sheets (CSS),与 JavaScript-style objects的内线风格,以及 JSS,一个用于创建 CSS 的库,使用 JavaScript

每个选项都依赖于 CSS 属性. 若要使用简单 CSS 而无需运行时间数据,您可以导入样式表. 如果您想要创建与组件集成的样式,您可以使用使用使用 CSS 属性名称作为密钥和样式作为值的线式样式对象。

为了说明这些方法,您将构建一个示例警告组件,该组件将根据 prop显示一个成功风格或一个错误风格。警告组件将使用任何数量的孩子。这意味着您需要对风格冲突保持谨慎,因为您没有办法知道儿童组件将有哪些风格。

前提条件

您将需要一个开发环境运行 Node.js;本教程已在 Node.js 版本 10.20.1 和 npm 版本 6.14.4 上测试;要在 macOS 或 Ubuntu 18.04 上安装此功能,请遵循 How to Install Node.js and Create a Local Development Environment on macOSHow to Install a React Project with Create React AppHow to Set Up a React Project with Create React App部分)中的步骤。 *您将需要能够使用 React 组件创建应用程序,您可以在我们的 How to Create Custom Components in React教程中找到与 Create React 一起安装

步骤 1 – 创建一个空的项目

在此步骤中,您将使用 [Create React App] 创建一个新项目(https://github.com/facebook/create-react-app)。然后您将删除在启动项目时安装的样本项目和相关文件。最后,您将创建一个简单的文件结构来组织您的组件。

要开始,创建一个新项目. 在终端中,运行以下脚本以使用create-react-app安装新项目:

1npx create-react-app styling-tutorial

项目完成后,更改到目录:

1cd styling-tutorial

在新的终端卡或窗口中,使用 Create React App start script启动项目。

1npm start

如果项目未在浏览器窗口中打开,您可以使用 http://localhost:3000/ 打开它。 如果您正在从远程服务器运行,则地址将是 http://your_domain:3000

您的浏览器将加载一个简单的 React 应用程序,作为 Create React 应用程序的一部分:

React template project

您将构建一组全新的自定义组件,因此您需要从清除一些锅炉板代码开始,以便您可以有一个空的项目。

要开始,请在文本编辑器中打开src/App.js。 这是注入到页面的根组件。 所有组件将从这里开始。 您可以找到有关App.js的更多信息,请参阅How To Set Up a React Project with Create React App(如何使用Create React App设置反应项目(LINK0))。

使用以下命令打开src/App.js:

1nano src/App.js

你會看到這樣的檔案:

 1[label styling-tutorial/src/App.js]
 2import React from 'react';
 3import logo from './logo.svg';
 4import './App.css';
 5
 6function App() {
 7  return (
 8    <div className="App">
 9      <header className="App-header">
10        <img src={logo} className="App-logo" alt="logo" />
11        <p>
12          Edit <code>src/App.js</code> and save to reload.
13        </p>
14        <a
15          className="App-link"
16          href="https://reactjs.org"
17          target="_blank"
18          rel="noopener noreferrer"
19        >
20          Learn React
21        </a>
22      </header>
23    </div>
24  );
25}
26
27export default App;

删除./logo.svg导入标签行,然后更换返回声明中的所有内容,以返回一组空标签:<></>

 1[label styling-tutorial/src/App.js]
 2
 3import React from 'react';
 4import './App.css';
 5
 6function App() {
 7  return <></>;
 8}
 9
10export default App;

保存和退出文本编辑器。

最后,删除标志. 你不会在你的应用程序中使用它,你应该在工作时删除未使用的文件。

在终端窗口中,输入以下命令:

1rm src/logo.svg

如果你看你的浏览器,你会看到一个空白的屏幕。

blank screen in chrome

现在您已经清理了 Create React App 样本项目,创建一个简单的文件结构,这将有助于保持您的组件隔离和独立。

src目录中创建一个名为components的目录,此目录将包含您的所有自定义组件。

1mkdir src/components

每个组件将有自己的目录来存储组件文件,以及风格,图像和测试。

创建一个App目录:

1mkdir src/components/App

将所有应用文件移动到该目录中。 使用 wildcard,以选择任何开始于应用的文件,无论文件的扩展,然后使用mv命令将其放入新目录:

1mv src/App.* src/components/App

接下来,更新index.js中的相对导入路径,这是启动整个过程的根组件:

1nano src/index.js

导入声明需要指向应用程序目录中的App.js文件,所以请做出以下突出更改:

 1[label styling-tutorial/src/index.js]
 2import React from 'react';
 3import ReactDOM from 'react-dom';
 4import './index.css';
 5import App from './components/App/App';
 6import * as serviceWorker from './serviceWorker';
 7
 8ReactDOM.render(
 9  <React.StrictMode>
10    <App />
11  </React.StrictMode>,
12  document.getElementById('root')
13);
14
15// If you want your app to work offline and load faster, you can change
16// unregister() to register() below. Note this comes with some pitfalls.
17// Learn more about service workers: https://bit.ly/CRA-PWA
18serviceWorker.unregister();

保存和退出文件。

现在项目已经设置,您可以创建您的第一个组件。

步骤 2 — 使用平面 CSS 来设计一个组件

在此步骤中,您将构建一个示例警告组件,该组件将在网页上显示警告。您将使用简单的CSS进行样式化,您将直接导入到组件中。这将确保组件的样式与组件的JavaScript和JSX密切相关(https://andsky.com/tech/tutorials/how-to-create-react-elements-with-jsx)。

到此步骤结束时,您将创建几个组件,这些组件使用直接导入到组件的简单 CSS。

构建一个警报组件

要开始,创建一个新的警报组件,首先,创建目录:

1mkdir src/components/Alert

接下来,打开Alert.js:

1nano src/components/Alert/Alert.js

添加一个返回警告字符串的基本组件:

1[label styling-tutorial/src/components/Alert/Alert.js]
2import React from 'react';
3
4export default function Alert() {
5  return <div>Alert</div>
6}

保存并关闭文件。

接下来,打开App.js:

1nano src/components/App/App.js

导入警报组件,并通过添加突出的代码将其转换为div:

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3import './App.css';
 4
 5import Alert from '../Alert/Alert';
 6
 7function App() {
 8  return (
 9    <div className="wrapper">
10      <Alert />
11    </div>
12  )
13}
14
15export default App;

在这个代码中,你给了div一个classNamewrapper,它将用于以后的风格。

当你这样做时,浏览器会更新,你会看到你的组件:

Browser with Alert

接下来,您将对应用程序组件进行格式化,以便给它一些粘贴,以便警报组件不那么接近边缘。

1nano src/components/App/App.css

这个文件使用标准的 CSS. 要添加包装,用一个规则代替默认代码,就像你在一个简单的HTML项目中的CSS一样。

1[label styling-tutorial/src/components/App/App.css]
2.wrapper {
3    padding: 20px;
4}

保存和关闭文件. 当你这样做时,页面将更新,你会看到额外的插件:

Browser with extra padding

当您使用Create React App时,webpack(https://webpack.js.org/)将导入的CSS并将其添加到浏览器中渲染的文件顶部的风格标签中。

Style tag in page source

这意味着您可以将 CSS 放在组件旁边,并且在 构建阶段中将被收集在一起。这也意味着您的样式在范围内是全球性的,这可能会产生潜在的名称冲突。

要探索此问题,您将对警报组件做一些更改。

首先,打开文件:

1nano src/components/Alert/Alert.js

然后添加一些React代码,将孩子类型标题作为赞助:

 1[label styling-tutorial/src/components/Alert/Alert.js]
 2import React from 'react';
 3import PropTypes from 'prop-types';
 4
 5export default function Alert({ children, title, type }) {
 6  return (
 7    <div>
 8      <h2>{title}</h2>
 9      {children}
10    </div>
11  )
12}
13
14Alert.propTypes = {
15  children: PropTypes.oneOfType([
16    PropTypes.arrayOf(PropTypes.element), 
17    PropTypes.element.isRequired
18  ]),
19  title: PropTypes.string.isRequired,
20  type: PropTypes.string.isRequired,
21}

本代码中的标题在一个<h2>标签中,而孩子将允许您显示儿童组件。您将很快使用类型标签来设置成功和错误警报,基于PropTypes打字系统(https://andsky.com/tech/tutorials/how-to-customize-react-components-with-props#step-3-%E2%80%94-creating-predictable-props-with-proptypes-and-defaultprops)。

保存并关闭文件. 接下来,更新应用中的警报组件以使用新的代理。

首先,打开App.js:

1nano src/components/App/App.js

创建警告,通知用户尝试将项目添加到购物车失败:

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3import './App.css';
 4
 5import Alert from '../Alert/Alert';
 6
 7function App() {
 8  return (
 9    <div className="wrapper">
10      <Alert title="Items Not Added" type="error">
11        <div>Your items are out of stock.</div>
12      </Alert>
13    </div>
14  )
15}
16
17export default App;

在此代码中,您更新了标题孩子的错误消息,然后添加了错误类型

当你这样做时,浏览器会更新,你会看到你的新组件:

Alert component

您的警报正在渲染,所以下一步是用 CSS 来设计组件。

将 CSS 添加到警报组件

由于警告组件丢失了错误,您将添加边界并将边界的颜色设置为红色。您还将给<h2>标签相同的颜色。

类名称冲突不是 CSS 中的一个新问题,并且曾有多次尝试使用命名公约(如 BEM)来解决它,但命名公约可能变得杂,并且在具有大量组件的项目中仍然有时会导致冲突。

在本教程中,您将使用由命名规则分开的特定规则集,而不是使用wrapper类名称以组件名称为前缀。

打开警报组件:

1nano src/components/Alert/Alert.js

接下来,添加以下突出的代码:

 1[label styling-tutorial/src/components/Alert/Alert.js]
 2import React from 'react';
 3import PropTypes from 'prop-types';
 4import './Alert.css';
 5...
 6export default function Alert({ children, type, title }) {
 7  return(
 8    <div className={`alert-wrapper ${type}`}>
 9      <h2>{title}</h2>
10      {children}
11    </div>
12  )
13}
14...

在这种情况下,您将警告包装器类型变量结合到一个单一的字符串中,使用模板字符串

保存和关闭文件. 现在你有一个独特的类名称,根据代码动态变化. 这个代码中的JSX将解决为一个div与类名称为alert-wrappererror

现在添加风格. 首先,打开警告组件的 CSS:

1nano src/components/Alert/Alert.css

将以下 CSS 添加到警告包裹成功错误类:

 1[label styling-tutorial/src/components/Alert/Alert.css]
 2
 3.alert-wrapper {
 4    padding: 15px;
 5    margin-bottom: 15px;
 6}
 7
 8.alert-wrapper h2 {
 9    margin: 0 0 10px 0;
10}
11
12.alert-wrapper.success {
13    border: #6DA06F solid 1px;
14}
15
16.success h2 {
17    color: #6DA06F;
18}
19
20.alert-wrapper.error {
21    border: #F56260 solid 1px;
22}
23
24.error h2 {
25    color: #F56260;
26}

此代码将添加一些边缘和插件到警告包装器中,然后将一个边界添加到错误类的红色阴影中,使用 hexidecimal 颜色代码#F56260,以及一个绿色阴影(#6DA06F')为成功`类。

保存和关闭文件. 当你这样做时,浏览器将更新,你会看到新的风格:

Styled error alert

现在你有一个警报组件,你可以创建一个新的组件,显示一个列表的项目在警报组件内。

创建成功信息组件

首先,为新组件CartSuccess创建一个目录:

1mkdir src/components/CartSuccess

打开CartSuccess.js:

1nano src/components/CartSuccess/CartSuccess.js

在组件内部,导入警报组件并传输包含用户已添加到篮子的一系列项目的<div>:

 1[label styling-tutorial/src/components/CartSuccess/CartSuccess.js]
 2import React from 'react';
 3import Alert from '../Alert/Alert';
 4import './CartSuccess.css';
 5
 6export default function CartSuccess() {
 7  return(
 8    <Alert title="Added to Cart" type="success">
 9      <div className="cart-success-wrapper">
10          <h2>
11            You have added 3 items:
12          </h2>
13          <div className="item">
14            <div>Bananas</div>
15            <div>Quantity: 2</div>
16          </div>
17          <div className="item">
18            <div>Lettuce</div>
19            <div>Quantity: 1</div>
20          </div>
21      </div>
22    </Alert>
23  )
24}

注意如何创建一个独特的类名称 - cart-success-wrapper - 为外部 <div>. 保存并关闭文件。

接下来,将一些CSS添加到自定义消息中,打开CartSuccess.css:

1nano src/components/CartSuccess/CartSuccess.css

添加 displayflex 到包装器. 您将希望大部分的项目被包装,除了 <h2> 元素,该元素应该占据整个宽度:

 1[label styling-tutorial/src/components/CartSuccess/CartSuccess.css]
 2.cart-success-wrapper {
 3    border-top: black solid 1px;
 4    display: flex;
 5    flex-wrap: wrap;
 6}
 7
 8.cart-success-wrapper h2 {
 9    width: 100%;
10}
11
12.item {
13    margin-right: 20px;
14}

在这里,您给了<h2>一个宽度为100%。除了弯曲元素之外,您还在消息的顶部添加了一个小边界,并为元素类增加了一个边界,以便在元素之间提供一些空间。

保存并关闭文件。

现在你有一个有风格的组件,请将其添加到你的应用组件中。

打开App.js:

1nano src/components/App/App.js

导入组件并在当前警报组件后添加它,如突出代码所示:

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3import './App.css';
 4
 5import Alert from '../Alert/Alert';
 6import CartSuccess from '../CartSuccess/CartSuccess';
 7
 8function App() {
 9  return(
10    <div className="wrapper">
11      <Alert title="Items Not Added" type="error">
12        <div>Your items are out of stock.</div>
13      </Alert>
14      <CartSuccess />
15    </div>
16  )
17}
18
19export default App;

当你这样做时,浏览器会更新,你会看到你的新组件:

Alerts in App

这显示了新颜色和预期的信息,但嵌入的组件收到了一些意想不到的风格。在警告组件中的<h2>规则正在应用到嵌入的<h2>标签在儿童附件中。

意想不到的风格随孩子们相连是CSS的一个常见问题,但是,由于React为您提供了在项目中组合和共享组件的机会,所以您有更大的潜力让风格无意中流入到儿童组件中。

要用纯粹的 CSS 来修复此问题,请为警报组件定义<h2>规则。

打开Alert.css文件:

1nano src/components/Alert/Alert.css

更改规则,以便<h2>的样式仅适用于班级的直接孩子,而不是使用CSS>的所有孩子(https://developer.mozilla.org/en-US/docs/Web/CSS/Child_combinator):

 1[label styling-tutorial/src/components/Alert/Alert.css]
 2.alert-wrapper {
 3    padding: 15px;
 4    margin-bottom: 15px;
 5}
 6
 7.alert-wrapper > h2 {
 8    margin: 0 0 10px 0;
 9}
10
11.alert-wrapper.success {
12    border: #6da06f solid 1px;
13}
14
15.success > h2 {
16    color: #6da06f;
17}
18
19.alert-wrapper.error {
20    border: #f56260 solid 1px;
21}
22
23.error > h2 {
24    color: #f56260;
25}

当你这样做时,页面会更新,你会看到CartSuccess中的<h2>元素保留默认颜色:

H2 with dark color

现在警告组件的风格只会影响直接的孩子,不会适用于其他儿童节点或组件. 在这种情况下,这种方法很好,但在组件更复杂的情况下,很难写出适用于所有情况的规则,而不会泄露到组件之外。

在此步骤中,您使用直接导入到组件的 CSS 样式表来样式化组件。使用标准 CSS 来样式化 React 元素是使用标准 CSS 文件创建具有相关风格的组件的快速方法。

当你构建组件时,你遇到两种常见的样式问题:类名称冲突和意想不到的样式应用程序. 你可以使用标准的CSS来处理这些问题,但还有其他样式方法可以为你提供工具来程序化处理这些问题,而不是使用命名惯例。

步骤 3 – 用风格对象的样式化

在此步骤中,您将使用 style objects 来格式化您的组件,即使用 CSS 属性作为密钥的 JavaScript 对象

单独的 CSS 是最常见的 HTML 样式方法. 这种方法是快速的,浏览器可以有效地快速和一致地应用样式. 但这不是 HTML 样式的唯一选择. 在标准的 HTML 中,您可以通过使用 样式属性与包含您想要应用的样式的字符串的元素直接设置内线样式。

风格对象的最佳用途之一是动态计算风格,如果您需要知道元素的当前位置,这尤其有用,因为直到元素被渲染才确定,因此只能动态处理。

手动编写风格字符串是很困难的,可以引入错误。缺少的颜色或半色彩会打破整个字符串。幸运的是,在 JSX 中,你不仅限于一个字符串,风格属性也可以接受包含风格的对象。

使用这样的内线风格的最大优点是,由于您正在使用JavaScript构建风格,您可以动态设置CSS属性,而不是动态设置类,这意味着您可以写代码而没有CSS类,避免潜在的名称冲突,并允许您在运行时计算风格。

若要使用风格对象,请先重构App.js

1nano src/components/App/App.js

在组件内部,删除导入的App.css文件,然后创建一个具有20padding的对象,然后使用style属性将对象传输到div>:

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3
 4import Alert from '../Alert/Alert';
 5import CartSuccess from '../CartSuccess/CartSuccess';
 6
 7function App() {
 8  const wrapper = {
 9    padding: 20
10  };
11
12  return(
13    <div style={wrapper}>
14      <Alert title="Items Not Added" type="error">
15        <div>Your items are out of stock.</div>
16      </Alert>
17      <CartSuccess />
18    </div>
19  )
20}
21
22export default App;

请注意,您不必指定像素作为插件的单位。 React 会默认地将此转换为一系列像素。 如果您想要一个特定的单位,请将其作为一个字符串传输。

大多数数字将自动转换为像素,但有一些例外。线高属性可以使用 无单位的平数

保存和关闭文件. 当你这样做时,浏览器将更新,你会看到页面就像以前一样:

Page with style object

接下来,重构器 CartSuccess. 首先,打开文件:

1nano src/components/CartSuccess/CartSuccess.js

App.js一样,删除已导入的 CSS(CartSuccess.css)并为以前包含类别的每个项目创建一个风格对象:

 1[label styling-tutorial/src/components/CartSuccess/CartSuccess.js]
 2import React from 'react';
 3import Alert from '../Alert/Alert';
 4
 5export default function CartSuccess() {
 6  const styles = {
 7    header: {
 8      width: '100%'
 9    },
10    item: {
11      marginRight: 20
12    },
13    wrapper: {
14      borderTop: 'black solid 1px',
15      display: 'flex',
16      flexWrap: 'wrap'
17    }
18  }
19
20  return(
21    <Alert title="Added to Cart" type="success">
22      <div style={styles.wrapper}>
23          <h2 style={styles.header}>
24            You have added 3 items:
25          </h2>
26          <div style={styles.item}>
27            <div>Bananas</div>
28            <div>Quantity: 2</div>
29          </div>
30          <div style={styles.item}>
31            <div>Lettuce</div>
32            <div>Quantity: 1</div>
33          </div>
34      </div>
35    </Alert>
36  )
37}

在这种情况下,您没有创建多个单独的对象;相反,您创建了一个包含其他对象的单个对象。

保存和关闭文件. 当您这样做时,页面将更新,您将看到具有相同风格的页面:

Page with style object

由于你不使用类,你不必担心任何名称冲突。使用JavaScript创建风格的另一个好处是,你可以利用任何JavaScript语法,如变量和模板字母。使用现代的CSS,你可以使用 变量,这是一个重大改进,但可能不完全可用,取决于你的浏览器的支持要求。特别是,它们在任何版本的Internet Explorer中都没有支持,尽管你可以使用 polyfill来添加支持。

由于风格对象是在运行时创建的,所以它们更可预测,并且可以使用任何支持的JavaScript。

若要查看风格对象如何在这种情况下有所帮助,请重构Alert.js以使用风格对象,首先打开Alert.js:

1nano src/components/Alert/Alert.js

Alert.js中,删除Import/Alert.css并创建一个名为colors的对象,该对象具有错误颜色的属性和成功颜色的属性。

 1[label styling-tutorial/src/components/Alert/Alert.js]
 2import React from 'react';
 3import PropTypes from 'prop-types';
 4
 5export default function Alert({ children, type, title }) {
 6  const colors = {
 7    success: '#6da06f',
 8    error: '#f56260',
 9  }
10
11  const style = {
12    heading: {
13      color: colors[type],
14      margin: '0 0 10px 0',
15    },
16    wrapper: {
17      border: `${colors[type]} solid 1px`,
18      marginBottom: 15,
19      padding: 15,
20      position: 'relative',
21    }
22  }
23
24  return(
25    <div style={style.wrapper}>
26      <h2 style={style.heading}>{title}</h2>
27      {children}
28    </div>
29  )
30}
31
32...

这里有一些变化. 首先,你使用一个单一的风格声明为包裹,然后动态地设置颜色基于类型. 你不是在格式化<h2>元素,而是在格式化这些特定的元素,这些元素是<h2>元素。

保存和关闭文件. 当你这样做时,浏览器将更新,你会看到应用的风格。

Page with style object

风格对象解决了许多问题,但它们确实有缺点。首先,有(Inline 风格的性能成本)。浏览器被设计用于有效地处理 CSS,并且应用Inline 风格的风格对象无法利用这些优化。 另一个问题是,在这种情况下,您不希望一个风格适用于儿童,但通常情况下,您希望在每个元素上设置自定义字体家族或在每个

元素上应用自定义大小,如果您使用了一个不太具体的风格策略,就更容易了。

然而,这些方法之间存在一个中间层面。 几个第三方库旨在找到这个中间层面。 在下一步中,您将使用名为 CSS-in-JS 的混合方法创建风格,使用名为 JSS 的库。

步骤 4 – 使用 JSS 进行样式化

在此步骤中,您将使用流行的库 JSS来设计对象。 您将安装新的库并将您的风格对象转换为 JSS 对象. 然后您将重构您的代码以使用动态生成的类名称,从而防止模块上的类名称之间的冲突。

JSS 是一个用于创建 CSS-in-JS 的库. 这种方法有许多(https://cssinjs.org/from-sass-to-cssinjs)不同的用例和选项,但本教程的主要优点是它将创建动态类名称,以避免组件之间的冲突。

首先,安装 React 特定版本的 JSS。本教程将使用版本 10.1.1:

1npm install react-jss

该包将安装多个依赖,包括一系列 JSS 插件,这将使您能够编写简要的风格规则。

安装完成后,您将看到一个成功消息:

1[secondary_label Output]
2+ [email protected]
3added 281 packages from 178 contributors, removed 142 packages, updated 1392 packages and audited 1025251 packages in 144.872s

您的输出将略有不同,取决于您的 Node 版本和其他依赖。

现在,库已安装,转换App.js以使用JSS。

1nano src/components/App/App.js

使用 JSS 有两个步骤. 首先,您需要导入一个函数来创建一个 custom hook。 Hooks 是 React 在每个组件渲染上运行的函数. 使用 JSS,您必须通过在组件外部的风格定义中输入来创建一个hook。

通过进行突出更改创建链接和风格对象:

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3import { createUseStyles } from 'react-jss';
 4
 5import Alert from '../Alert/Alert';
 6import CartSuccess from '../CartSuccess/CartSuccess';
 7
 8const useStyles = createUseStyles({
 9  wrapper: {
10    padding: 20,
11  }
12});
13
14function App() {
15  return(
16    <div>
17      <Alert title="Items Not Added" type="error">
18        <div>Your items are out of stock.</div>
19      </Alert>
20      <CartSuccess />
21    </div>
22  )
23}
24
25export default App;

在这种情况下,请注意,您的风格对象包含另一个名为wrapper的对象,该对象包含使用相同的骆驼形状格式的风格。

创建链接后,您将通过在组件内部执行函数来消耗链接。这会记录链接并动态地创建风格。

 1[label styling-tutorial/src/components/App/App.js]
 2import React from 'react';
 3import { createUseStyles } from 'react-jss'
 4
 5import Alert from '../Alert/Alert';
 6import CartSuccess from '../CartSuccess/CartSuccess';
 7
 8const useStyles = createUseStyles({
 9  wrapper: {
10    padding: 20,
11  }
12});
13
14function App() {
15  const classes = useStyles()
16  return(
17    <div className={classes.wrapper}>
18      <Alert title="Items Not Added" type="error">
19        <div>Your items are out of stock.</div>
20      </Alert>
21      <CartSuccess />
22    </div>
23  )
24}
25
26export default App;

在此代码中,你调用函数并将结果分配给一个名为的变量。新的变量将是一个包含动态类名称的对象。

保存和关闭文件. 当你这样做时,浏览器将更新,你会看到与之前相同的风格. 但如果你看看控制台,你会看到类的名称不完全匹配你在你的对象中定义的名称:

Styles with applied class names

在这种情况下,类名称是wrapper-0-2-1,但您的类名称可能不同. 您还会看到风格从对象转换为 CSS,并放入一个<style>标签。

JSS 动态地创建类名称,以便它们不会与其他文件中的类似名称发生冲突. 要在工作中看到这一点,请使用 refactor CartSuccess.js 使用 JSS 样式。

打开文件:

1nano src/components/CartSuccess/CartSuccess.js

在文件中,使用「CreateUseStyles」创建一个自定义链接,而不是将类应用到「

」元素中,您将为包装器中的「

」元素创建一个规则。

使用 JSS,您可以通过在包含元素中创建另一个对象来创建类似的规则。

 1[label styling-tutorial/src/components/CartSuccess/CartSuccess.js]
 2import React from 'react';
 3import { createUseStyles } from 'react-jss';
 4import Alert from '../Alert/Alert';
 5
 6const useStyles = createUseStyles({
 7  item: {
 8    marginRight: 20
 9  },
10  wrapper: {
11    borderTop: 'black solid 1px',
12    display: 'flex',
13    flexWrap: 'wrap',
14    '& h2': {
15      width: '100%'
16    }
17  }
18})
19
20export default function CartSuccess() {
21  const classes = useStyles();
22  return(
23    <Alert title="Added to Cart" type="success">
24      <div className={classes.wrapper}>
25          <h2>
26            You have added 3 items:
27          </h2>
28          <div className={classes.item}>
29            <div>Bananas</div>
30            <div>Quantity: 2</div>
31          </div>
32          <div className={classes.item}>
33            <div>Lettuce</div>
34            <div>Quantity: 1</div>
35          </div>
36      </div>
37    </Alert>
38  )
39}

除了为包装器创建规则外,您还为项目创建了规则.创建自定义链接后,您将自定义类名称传递到className属性。

请注意,您在该组件和应用程序组件中使用相同的名称――wrapper(包装)――但当浏览器重新加载时,不会出现命名冲突;一切都将看起来正确。

Image with multiple wrapper classes

在这种情况下,外部组件的类为wrapper-0-2-1,它是在应用组件中生成的。CartSuccess的类为wrapper-0-2-3

在某些情况下,您可能需要创建一个特定的选择器来取代其他风格,例如,假设您只希望在元素属于包装类的孩子时应用元素样式。

 1[label styling-tutorial/src/components/CartSuccess/CartSuccess.js]
 2import React from 'react';
 3import { createUseStyles } from 'react-jss'
 4import Alert from '../Alert/Alert';
 5
 6const useStyles = createUseStyles({
 7  item: {},
 8  wrapper: {
 9    borderTop: 'black solid 1px',
10    display: 'flex',
11    flexWrap: 'wrap',
12    '& h2': {
13      width: '100%'
14    },
15    '& $item': {
16      marginRight: 20
17    }
18  }
19})
20
21export default function CartSuccess() {
22  const classes = useStyles()
23  return(
24    <Alert title="Added to Cart" type="success">
25      <div className={classes.wrapper}>
26          <h2>
27            You have added 3 items:
28          </h2>
29          <div className={classes.item}>
30            <div>Bananas</div>
31            <div>Quantity: 2</div>
32          </div>
33          <div className={classes.item}>
34            <div>Lettuce</div>
35            <div>Quantity: 1</div>
36          </div>
37      </div>
38    </Alert>
39  )
40}

当浏览器重新加载时,页面将看起来相同,但项目CSS将更具体地应用于包装组件下的项目:

Item class applied

JSS 允许您创建与常规 CSS 创建相同的焦点级别的规则,但同时创建不会碰撞的独特类名称。

JSS的最后一个优点是,你有能力使用变量和其他JavaScript语言功能. 由于你正在使用react-jss,你可以向风格对象传递优惠,以创建动态风格。

首先,打开文件:

1nano src/components/Alert/Alert.js

请确保将定义颜色的对象移动到组件函数之外,以便它与CreateUseStyles函数相同的范围(https://andsky.com/tech/tutorials/understanding-variables-scope-hoisting-in-javascript#variable-scope):

 1[label styling-tutorial/src/components/Alert/Alert.js]
 2import React from 'react';
 3import PropTypes from 'prop-types';
 4import { createUseStyles } from 'react-jss';
 5
 6const colors = {
 7  success: '#6da06f',
 8  error: '#f56260',
 9};
10
11const useStyles = createUseStyles({
12    wrapper: {
13      border: ({ type }) => `${colors[type]} solid 1px`,
14      marginBottom: 15,
15      padding: 15,
16      position: 'relative',
17      '& h2': {
18        color: ({ type }) => colors[type],
19        margin: [0, 0, 10, 0],
20      }
21    }
22});
23
24export default function Alert({ children, type, title }) {
25  const classes = useStyles({ type })
26  return(
27    <div className={classes.wrapper}>
28      <h2>{title}</h2>
29      {children}
30    </div>
31  )
32}
33
34...

要通过赞助,你会把风格规则变成一个函数。该函数接受赞助作为一个参数,然后返回一个规则。 要创建一个动态边界,你会将边界添加为属性名称,并将箭头函数(https://andsky.com/tech/tutorials/how-to-define-functions-in-javascript#arrow-functions)添加到类型并返回一个字符串:({类型 }) =>${颜色[类型]固体1px``。 然后,在创建你的链接后,你会将创建类对象时想要参考的赞助符串传输。 就像以前一样,你将`

标签为元素,而不是创建特定类别。

保存文件. 请注意,您不必将所有特许权传输到函数中。 在这种情况下,您只需要使用类型,所以这就是您需要传输的全部。 但是,您可以传输更多或甚至传输未知特许权使用剩余操作员来收集特许权,然后传输作为一个组。

当页面重新加载时,你会看到正确的颜色,但会有一个小问题:绿色成功颜色现在正在更新CartSuccess中的<h2>元素:

H2 is green

JSS解决了许多问题,但它仍然创建了标准的CSS,这意味着如果您不小心,可以将风格应用于儿童元素。

 1[label styling-tutorial/src/components/Alert/Alert.js]
 2import React from 'react';
 3...
 4const useStyles = createUseStyles({
 5    wrapper: {
 6      border: ({ type }) => `${colors[type]} solid 1px`,
 7      marginBottom: 15,
 8      padding: 15,
 9      position: 'relative',
10      '& > h2': {
11        color: ({ type }) => colors[type],
12        margin: [0, 0, 10, 0],
13      }
14    }
15});
16
17export default function Alert({ children, type, title }) {
18
19...
20
21}
22
23...

保存和关闭文件. 当你这样做时,浏览器将重新加载,你会看到正确的风格:

H2 with dark color

JSS 比本教程所涵盖的要多得多。我们没有触及的一个重要优点是 theming。 JSS 让您能够基于预定义主题对象创建风格,这意味着,而不是从硬编码值创建红色,您可以将警报边界变成警报颜色,这很可能是一个红色的阴影,但可能因主题定义而有所不同。

在此步骤中,您使用第三方库名为react-jss来造型组件,您还创建了样式对象,并使用JSS将这些对象转换为动态类,以避免与其他组件发生冲突。

结论

在本教程中,您已经开发了几种可重复使用的组件,这些组件使用不同的风格技术。您已经了解到风格对象和JSS如何使用使用密切反映标准CSS属性的名称创建对象,并创建了能够动态设置风格的组件,基于收入属性。

与大多数 React 技术一样,没有单一的最佳解决方案。相反,您可以选择最适合您的项目的风格选项. 有了这些选项,您可以开始做一些简单和重塑性的事情,随着项目的增长或需求的变化,同时保持信心,您的组件将继续满足您的风格目标。

如果您想查看更多 React 教程,请查看我们的 React 主题页面,或返回 如何在 React.js 系列中编码页面

Published At
Categories with 技术
comments powered by Disqus