迭代使用样式组件的React设计
理想情况下,项目拥有无限资源和时间。团队将使用经过深思熟虑且高度优化的 UX 设计开始编码。开发人员之间将就最佳样式方法达成共识。团队中将有一位或多位 CSS 专家,他们可以确保功能和样式可以同时推出,而不会变成一团糟。
我确实在大型企业环境中见过这种情况。这是一件美好的事情。本文不适用于这些人。
另一方面,小型初创公司资金为零,只有一到两位前端开发人员,而且展示某些功能的时间非常短。它不必看起来完美,但至少应该在台式机、平板电脑和移动设备上合理地呈现。这使他们能够将其展示给顾问和早期用户;甚至可能是对该概念表示感兴趣的潜在投资者。一旦他们从销售和/或投资中获得一些现金流,他们就可以获得专门的 UX 设计师并改进界面。
以下内容适用于后一组人员。
项目启动会议
让我们发明一家公司来启动项目。
Solar Excursions 是一家小型旅行社,旨在服务于近未来蓬勃发展的太空旅游业。
我们的小型开发团队已同意将 React 用于 UI。我们的一位前端开发人员非常喜欢 Sass,而另一位则迷恋于 JavaScript 中的 CSS。但是他们很难完成最初的冲刺目标;当然没有时间争论最佳的样式方法。两位编码员都同意,从长远来看,选择并不重要,只要它得到一致执行即可。他们确信,现在在压力下从头开始实现样式将导致技术债务,以后必须清理。
经过一番讨论,团队选择规划一个或多个“样式重构”冲刺。现在,我们将专注于使用 React-Bootstrap 在屏幕上显示一些内容。这样,我们就可以快速构建有效的桌面和移动布局,而无需大费周章。
在前端样式上花费的时间越少越好,因为我们还需要将 UI 连接到我们的后端开发人员将要推出的服务。而且,随着我们的应用程序架构开始成形,两位前端开发人员都同意对其进行单元测试非常重要。他们有很多事情要做。
根据我与当权者的讨论,作为一名专门的项目经理,我至少在 Balsamiq 上辛苦工作了十分钟,为团队提供了台式机和移动设备上预订页面的模型。我认为他们将在中间满足平板电脑的要求,并且看起来很合理。
第零次冲刺:审查会议
到处都是比萨饼!团队非常努力地实现了其目标,我们现在有一个布局近似于模型的预订页面。服务的架构正在形成,但在我们可以将其连接到 UI 之前还有很长的路要走。在此期间,前端开发人员正在使用硬编码的模拟数据结构。
以下是我们迄今为止的 UI 代码:
这都是简单的 React。我们正在使用一些 Hooks 热门技术,但对你们大多数人来说,这可能已经过时了。
需要注意的关键要点是,我们的五个应用程序组件中有四个导入并使用了来自 react-bootstrap 的组件。只有主要的 App 组件不受影响。这是因为它只是使用我们的自定义组件组合顶级视图。
<code>// App.js imports import React, { useState } from "react"; import Navigation from "./Navigation"; import Page from "./Page"; // Navigation.js imports import React from "react"; import { Navbar, Dropdown, Nav } from "react-bootstrap"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { Container, Row, Col } from "react-bootstrap"; // PosterCarousel.js imports import React from "react"; import { Alert, Carousel, Image } from "react-bootstrap"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { Button, Card, Col, Container, Dropdown, Jumbotron, ListGroup, Row, ToggleButtonGroup, ToggleButton } from "react-bootstrap";</code>
使用 Bootstrap 快速行动的决定使我们能够实现冲刺目标,但我们已经在积累技术债务。这只是四个受影响的组件,但随着应用程序的增长,很明显,我们计划的“样式重构”冲刺将变得越来越困难。我们甚至没有对这些组件进行太多自定义。一旦我们拥有数十个组件,所有组件都使用 Bootstrap 并使用大量内联样式来美化它们,将它们重构以删除 react-bootstrap 依赖项将是一个非常可怕的主张。
与其构建更多预订管道页面,团队决定我们将花费下一个冲刺来隔离自定义组件工具包中的 react-bootstrap 使用情况,因为我们的服务仍在构建中。应用程序组件将仅使用此工具包中的组件。这样,当我们从 react-bootstrap 中分离出来时,这个过程就会容易得多。我们不必在整个应用程序中重构三十个 react-bootstrap Button 的用法,我们只需重写 KitButton 组件的内部即可。
第一次冲刺:审查会议
好吧,这很容易。击掌。UI 的视觉外观没有变化,但我们现在有一个“kit”文件夹,它是我们 React 源代码中“components”的同级文件夹。它有很多文件,例如 KitButton.js,它基本上导出重命名的 react-bootstrap 组件。
我们工具包中的一个示例组件如下所示:
<code>// KitButton.js import { Button, ToggleButton, ToggleButtonGroup } from "react-bootstrap"; export const KitButton = Button; export const KitToggleButton = ToggleButton; export const KitToggleButtonGroup = ToggleButtonGroup;</code>
我们将所有工具包组件打包到这样的模块中:
<code>// kit/index.js import { KitCard } from "./KitCard"; import { KitHero } from "./KitHero"; import { KitList } from "./KitList"; import { KitImage } from "./KitImage"; import { KitCarousel } from "./KitCarousel"; import { KitDropdown } from "./KitDropdown"; import { KitAttribution } from "./KitAttribution"; import { KitNavbar, KitNav } from "./KitNavbar"; import { KitContainer, KitRow, KitCol } from "./KitContainer"; import { KitButton, KitToggleButton, KitToggleButtonGroup } from "./KitButton"; export { KitCard, KitHero, KitList, KitImage, KitCarousel, KitDropdown, KitAttribution, KitButton, KitToggleButton, KitToggleButtonGroup, KitContainer, KitRow, KitCol, KitNavbar, KitNav };</code>
现在我们的应用程序组件完全没有 react-bootstrap。以下是受影响组件的导入:
<code>// Navigation.js imports import React from "react"; import { KitNavbar, KitNav, KitDropdown } from "../kit"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { KitContainer, KitRow, KitCol } from "../kit"; // PosterCarousel.js imports import React from "react"; import { KitAttribution, KitImage, KitCarousel } from "../kit"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { KitCard, KitHero, KitList, KitButton, KitToggleButton, KitToggleButtonGroup, KitDropdown, KitContainer, KitRow, KitCol } from "../kit";</code>
以下是我们现在的前端代码库:
尽管我们将所有 react 导入都包含在我们的工具包组件中,但我们的应用程序组件仍然依赖于 react-bootstrap 实现,因为我们放置在工具包组件实例上的属性与 react-bootstrap 的属性相同。这在重新实现工具包组件时会限制我们,因为我们需要遵守相同的 API。例如:
<code>// 来自 Navigation.js <kitnavbar bg="dark" fixed="top" variant="dark"></kitnavbar></code>
理想情况下,当我们实例化 KitNavbar 时,我们不必添加那些 react-bootstrap 特定的属性。
前端开发人员承诺在继续进行时将这些属性重构出来,因为我们已经将它们识别为有问题的。任何对 react-bootstrap 组件的新引用都将进入我们的工具包,而不是直接进入应用程序组件。
同时,我们将我们的模拟数据与服务器工程师共享,服务器工程师正在努力构建单独的服务器环境、实现数据库模式并向我们公开一些服务。
这给了我们时间在下一个冲刺中为我们的 UI 添加一些光泽——这很好,因为当权者希望看到每个目的地的单独主题。当用户浏览目的地时,我们需要更改 UI 配色方案以匹配显示的旅行海报。此外,我们希望尝试改进这些组件,以开始发展我们自己的外观和感觉。一旦我们有一些收入,我们将请设计师进行全面检修,但希望我们能够为早期用户找到一个合适的方案。
第二次冲刺:审查会议
哇!团队在这个冲刺中确实竭尽全力。我们获得了每个目的地的主题、自定义组件以及从应用程序组件中删除了许多残留的 react-bootstrap API 实现。
以下是现在的桌面外观:
为了实现这一点,前端开发人员引入了 Styled Components 库。它使为各个工具包组件设置样式以及添加对多个主题的支持变得轻而易举。
让我们看看他们本冲刺中的一些亮点。
首先,对于导入字体和设置页面正文样式之类的全局内容,我们有一个名为 KitGlobal 的新工具包组件。
<code>// KitGlobal.js import { createGlobalStyle } from "styled-components"; export const KitGlobal = createGlobalStyle` body { @import url('https://fonts.googleapis.com/css?family=Orbitron:500|Nunito:600|Alegreya Sans SC:700'); background-color: ${props => props.theme.foreground}; overflow-x: hidden; } `;</code>
它使用 createGlobalStyle 辅助函数来定义 body 元素的 CSS。它从 Google 导入我们所需的网络字体,将背景颜色设置为当前主题的“前景”值,并关闭 x 方向上的溢出以消除讨厌的水平滚动条。我们在 App 组件的 render 方法中使用 KitGlobal 组件。
同样在 App 组件中,我们从 ../theme 导入 ThemeProvider 来自 styled-components,以及名为“themes”的内容。我们使用 React 的 useState 将初始主题设置为 themes.luna,并使用 React 的 useEffect 在“destination”更改时调用 setTheme。返回的组件现在包装在 ThemeProvider 中,后者将“theme”作为 prop 传递。以下是完整的 App 组件。
<code>// App.js import React, { useState, useEffect } from "react"; import { ThemeProvider } from "styled-components"; import themes from "../theme/"; import { KitGlobal } from "../kit"; import Navigation from "./Navigation"; import Page from "./Page"; export default function App(props) { const [destinationIndex, setDestinationIndex] = useState(0); const [theme, setTheme] = useState(themes.luna); const destination = props.destinations[destinationIndex]; useEffect(() => { setTheme(themes[destination.theme]); }, [destination]); return ( <themeprovider theme="{theme}"><react.fragment><kitglobal></kitglobal><navigation destinationindex="{destinationIndex}" setdestinationindex="{setDestinationIndex}"></navigation><page destinationindex="{destinationIndex}" setdestinationindex="{setDestinationIndex}"></page></react.fragment></themeprovider> ); }</code>
KitGlobal 像任何其他组件一样呈现。那里没有什么特别的,只是 body 标签受到影响。ThemeProvider 使用 React Context API 将主题传递给任何需要它的组件(所有组件)。为了完全理解这一点,我们还需要看看主题究竟是什么。
为了创建一个主题,我们的一位前端开发人员获取了所有旅行海报,并通过提取突出的颜色为每个海报创建调色板。这相当简单。
显然,我们不会使用所有颜色。该方法主要是将最常用的两种颜色命名为前景和背景。然后我们又取了三种颜色,通常从最浅到最深排列为 accent1、accent2 和 accent3。最后,我们选择了两种对比色来命名 text1 和 text2。对于上述目的地,这看起来像:
<code>// theme/index.js (部分列表) const themes = { ... mars: { background: "#a53237", foreground: "#f66f40", accent1: "#f8986d", accent2: "#9c4952", accent3: "#f66f40", text1: "#f5e5e1", text2: "#354f55" }, ... }; export default themes;</code>
一旦我们为每个目的地创建了一个主题,并且它被传递到所有组件(包括我们的应用程序组件现在从中构建的工具包组件),我们就需要使用 styled-components 来应用这些主题颜色以及我们的自定义视觉样式,例如面板角和“边框辉光”。
这是一个简单的示例,我们让 KitHero 组件将主题和自定义样式应用于 Bootstrap Jumbotron:
<code>// KitHero.js import styled from "styled-components"; import { Jumbotron } from "react-bootstrap"; export const KitHero = styled(Jumbotron)` background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Nunito", sans-serif; margin-bottom: 20px; `;</code>
在这种情况下,我们可以使用 styled-components 返回的内容,因此我们只需将其命名为 KitHero 并导出即可。
当我们在应用程序中使用它时,它看起来像这样:
<code>// DestinationLayout.js (部分代码) const renderHero = () => { return ( <kithero><h2 id="destination-header">{destination.header}</h2> <p>{destination.blurb}</p> <kitbutton>Book Your Trip Now!</kitbutton></kithero> ); };</code>
然后还有更复杂的情况,我们希望预设 react-bootstrap 组件上的一些属性。例如,前面我们已经确定 KitNavbar 组件具有一堆我们宁愿不从应用程序的组件声明中传递的 react-bootstrap 属性。
现在让我们看看是如何处理的:
<code>// KitNavbar.js (部分代码) import React, { Component } from "react"; import styled from "styled-components"; import { Navbar } from "react-bootstrap"; const StyledBootstrapNavbar = styled(Navbar)` background-color: ${props => props.theme.background}; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; display: flex; flex-direction: horizontal; justify-content: space-between; font-family: "Nunito", sans-serif; `; export class KitNavbar extends Component { render() { const { ...props } = this.props; return ; } }</code>
首先,我们使用 styled-components 创建一个名为 StyledBootstrapNavbar 的组件。我们可以使用传递给 styled-components 的 CSS 来处理一些属性。但是,为了继续利用(目前)组件对屏幕顶部的可靠粘性(而其他所有内容都被滚动),我们的前端开发人员选择继续使用 react-bootstrap 的 fixed 属性。为了做到这一点,我们必须创建一个 KitNavbar 组件,该组件使用 fixed=top 属性呈现 StyledBootstrapNavbar 的实例。我们还传递了所有 props,其中包括它的子元素。
如果我们想通过默认值在工具包组件中显式设置某些属性,我们只需要创建一个单独的类来呈现 styled-component 的工作并将 props 传递给它即可。在大多数情况下,我们只需命名和返回 styled-component 的输出并像上面对 KitHero 所做的那样使用它即可。
现在,当我们在应用程序的 Navigation 组件中呈现 KitNavbar 时,它看起来像这样:
<code>// Navigation.js (部分代码) return ( <kitnavbar><kitnavbarbrand><kitlogo></kitlogo> Solar Excursions </kitnavbarbrand> {renderDestinationMenu()} </kitnavbar> );</code>
最后,我们第一次尝试将工具包组件从 react-bootstrap 中重构出来。KitAttribution 组件是一个 Bootstrap Alert,就我们的目的而言,它只不过是一个普通的 div。我们能够轻松地重构以删除其对 react-bootstrap 的依赖性。
这是从上一个冲刺中出现的组件:
<code>// KitAttribution.js (使用 react-bootstrap) import { Alert } from "react-bootstrap"; export const KitAttribution = Alert;</code>
这就是它现在的样子:
<code>// KitAttribution.js import styled from "styled-components"; export const KitAttribution = styled.div` text-align: center; background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Alegreya Sans SC", sans-serif; > a { color: ${props => props.theme.text2}; font-family: "Nunito", sans-serif; } > a:hover { color: ${props => props.theme.background}; text-decoration-color: ${props => props.theme.accent3}; } `;</code>
请注意,我们不再导入 react-bootstrap,而是使用 styled.div 作为组件基础。它们不会都那么容易,但这是一个过程。
以下是我们的团队在本冲刺中进行的样式和主题设计工作的结果:
在此处查看主题页面本身。
结论
经过三个冲刺后,我们的团队正在顺利构建 UI 的可扩展组件架构。
- 由于 react-bootstrap,我们正在快速前进,但不再因此积累大量的技术债务。
- 由于 styled-components,我们能够实现多个主题(就像如今互联网上的几乎每个应用程序都具有深色和浅色模式一样)。我们也不再像一个现成的 Bootstrap 应用程序了。
- 通过实现一个包含所有对 react-bootstrap 的引用的自定义组件工具包,我们可以根据需要进行重构。
在 GitHub 上分叉最终代码库。
以上是迭代使用样式组件的React设计的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...
