在 React 应用程序中使用 Grommet
已发表: 2022-03-10多年来,随着帮助开发 React 应用程序的库的发明,React 生态系统不断发展。 在本教程中,我们将学习使用 Grommet 为 React 应用程序开发响应式、可访问性和移动优先的组件。 我们将仔细研究它的核心概念、一些用例,并构建一个简单的示例。 需要注意的是,Grommet 是开源的,在 GitHub 上有 6.9k 星。
本教程将对有兴趣使用 Grommet 在其 React 应用程序中开发响应式组件的读者有所帮助。 本文需要对 React 和 Styled-components 有基本的了解。
什么是索环?
Grommet 是一个 React 组件库,它拥有响应式和可访问的移动优先代码组件。 它通过它的组件来做到这一点——这些组件是库的构建块。 它们包括布局、类型、颜色、控件、输入、可视化媒体和实用程序。 所有索环组件都是内置的,考虑到了可访问性和响应性。
Grommet 提供对 W3C 规范的支持,这使得它在可访问性方面得分很高。 它还提供强大的主题和工具,允许您根据项目需要自定义颜色、类型、组件元素和布局需求。
Grommet 的一些流行替代品包括 tailwindcss 和样式化组件,虽然在开发人员中非常流行,但每个框架在构建应用程序的方法上有所不同。 Grommet 是移动优先、可访问、响应式和开箱即用的主题,并且支持 W3C 以轻松创建 React 应用程序,而 Tailwind CSS 是一个高度可定制和实用的框架,允许开发人员构建应用程序而不受 CSS 的限制,例如其级联规则。 Styled-components 旨在帮助开发人员编写可重用的 React 组件,允许我们使用对象文字在 JavaScript 中编写 CSS 代码,并且它还使用组件作为低级样式构造。
在我们的项目中,我们将在我们的项目中使用 Grommet,因为它具有可定制的组件、可访问性和主题属性,这是我们在本教程中继续进行时所需要的。
使用索环组件
与许多其他组件库一样,Grommet 预构建了一些用于布局和主题的组件,例如 Box、Card 和 Header 组件。 要首先使用,您需要使用 NPM 或 yarn 安装 grommet 包,如下面的代码块。
npm i grommet styled-components
要么:
yarn add grommet styled-components
从上面可以看出我们也安装了styled-components。 这是因为 Grommet 使用 styled-components 来自定义组件中的样式; 建议在您的项目中安装 styled-components。
要在 React 项目中使用 Grommet 组件,您需要导入grommet
。 下面我们构建一个卡片组件来解释:
import React from 'react'; import { Grommet, Card } from 'grommet'; export default function GrommetExample() { return ( <Card> <CardBody pad="medium">Body</CardBody> <Button icon={<Icons.Favorite color="red" />} hoverIndicator /> </Card> ); }
在上面的代码块中,首先将Grommet
和从grommet
包中的Card
组件导入到您的文件中,接下来我们使用我们导入的Card
组件包装我们的组件。 样式可以像我们对Button
一样作为对象添加到 Grommet 组件,也可以使用 styled-components 设置样式。
让我们通过查看 Form 组件来了解更多有关 Grommet 组件的示例。
为什么是索环?
Grommet 的主要目的是改善开发人员的体验,并通过其移动优先、可访问和响应式组件以更快的方式构建 React 应用程序。 Grommet 将设计和开发人员工作流程无缝对齐,以创建无缝体验,让任何人都可以轻松上手。
Grommet 还为开箱即用的屏幕阅读器提供支持,诸如暗模式之类的主题变体是从开箱即用的themeMode
中获得的,并且可以使用 React 应用程序中的 themeMode 属性进行设置,如下所示。
import React from "react"; import { Grommet, Box, Button, Heading, dark } from "grommet"; import { grommet } from "grommet"; const App = () => { const [darkMode, setDarkMode] = React.useState(false); return ( <Grommet full theme={grommet} themeMode={darkMode ? "dark" : "light"}> <Box pad="large"> <Heading level="1">Grommet Darkmode toggle</Heading> <Button label="Toggle Theme" primary alignSelf="center" margin="large" onClick={() => setDarkMode(!darkMode)} /> </Box> </Grommet> ); }; export default App;
在上面的代码块中,我们使用themeMode
属性来添加暗模式。 使用三元运算符,我们检查页面是否处于暗模式,我们可以将其切换到亮模式,接下来我们在应用程序中添加了一个用于在亮模式和暗模式之间切换的按钮,您可以在此处查看 Codesandbox 上的演示。
Grommet 也可以与其他框架一起存在,并且不会添加会影响 React 应用程序中现有组件的全局样式,函数和样式可以插入到样式的对象文字中。 Grommet 还具有 Layout 组件,它具有一些 CSS 属性,例如 flexbox,它还接受所有 flexbox 属性作为 props。
与许多其他框架不同,Grommet 具有一个大型 SVG 图标库,可使用<Icon />
组件访问。 Grommet 具有用于数据可视化的组件,例如条形图、地图甚至进度跟踪器。
今天有几家公司使用 Grommet 创建现实世界的应用程序,包括 Netflix、IBM、Sony、Samsung、Shopify、GitHub 和 Twilio。
使用索环构建定价组件
现在我们了解了 Grommet 的基础知识和核心概念,我们将使用 Grommet 组件创建一个定价组件,它应该包含来自 Grommet 库的 Card、Box 和 Buttons 等组件。
事不宜迟,让我们开始吧!
设置您的环境
首先,让我们创建一个裸 React 应用程序,在终端上编写下面的代码块。
create-react-app grommet-app
上面的代码将使用 create-react-app 包创建一个裸 React 应用程序。 进入项目目录。
cd grommet-app
接下来是安装我们在项目中需要的依赖项。
yarn add grommet styled-components
如果您已完成此操作,请使用以下命令启动项目服务器。
yarn start
对于这个项目,我们需要一个带有样式组件的卡片和样式组件。
让我们在下面创建第一张卡片
import React from "react"; import styled from "styled-components"; export default function GrommetCard() { return ( <> <CardWrapper> <Card left> <Div> <Div> <CardContent> <small>Basic</small> <h1>$588</h1> </CardContent> <CardContent> <p>500 GB storage</p> </CardContent> <CardContent> <p>2 Users Allowed</p> </CardContent> <CardContent> <p>Send Up To 3 GB</p> </CardContent> </Div> <CardButton secondary>LEARN MORE</CardButton> </Div> </Card> </CardWrapper> </> ); }
在上面的代码块中,我们使用组件CardWrapper
来包装我们所有的Card
组件,接下来我们添加了一个新组件CardContent
,它用于包装每个卡片组件中的所有内容。 CardButton
组件是在 Grommet 上的卡片上使用的按钮组件。
接下来,让我们使用 styled-components 为我们的应用程序创建样式。 在下面写入文件:
const primaryGradient = "linear-gradient(hsl(236, 72%, 79%), hsl(237, 63%, 64%))"; const CardWrapper = styled.div` display: flex; justify-content: center; align-items: center; height: max-content; margin: 20px; @media all and (max-width: 1240px) { flex-direction: column; } `;
在上面,我们在应用程序中为CardWrapper
定义了一个样式对象。 让我们为上面的 Card 组件添加样式对象。
const Card = styled.div` min-width: 380px; box-shadow: 3px -2px 19px 0px rgba(50, 50, 50, 0.51); border-radius: ${(props) => (props.left ? " 6px 0 0 6px" : props.right ? "0 6px 6px 0" : "6px")}; background: ${(props) => (props.secondary === undefined ? "#fff" : primaryGradient)}; padding: 25px 20px; height: ${(props) => (props.center ? "520px" : "480px")}; display: flex; justify-content: center; align-items: center; @media all and (max-width: 1240px) { margin-bottom: 20px; border-radius: 6px; height: 480px; } @media all and (max-width: 420px) { min-width: 90%; } `;
让我们为我们的组件添加更多样式。
const CardButton = styled.div` min-width: 100%; padding: 10px 15px; min-height: 50px; box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2), 0px 0px 2px rgba(0, 0, 0, 0.2); color: ${(props) => (props.secondary !== undefined ? "#fff" : "#7c7ee3")}; background: ${(props) => (props.secondary === undefined ? "#fff" : primaryGradient)}; text-align: center; margin-top: 25px; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 16px; border-radius: 6px; `; const CardContent = styled.div` width: 100%; color: ${(props) => (props.secondary !== undefined ? "#fff" : "#000")}; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1.3px solid #eee; text-align: center; `; const Div = styled.div` min-width: 100%; `;
完成所有这些后,我们的项目应该类似于下图。
我们需要使用下面的代码块向我们的组件添加更多卡片。
<Card center secondary> <Div> <Div> <CardContent secondary> <small>Premium</small> <h1>$788</h1> </CardContent> <CardContent secondary> <p>75 GB storage</p> </CardContent> <CardContent secondary> <p>4 Users Allowed</p> </CardContent> <CardContent secondary> <p>Send Up To 5 GB</p> </CardContent> </Div> <CardButton>LEARN MORE</CardButton> </Div> </Card> <Card right> <Div> <Div> <CardContent> <small>PRO</small> <h1>$1000</h1> </CardContent> <CardContent> <p>1TB storage</p> </CardContent> <CardContent> <p>Unlimited Users Allowed</p> </CardContent> <CardContent> <p>Send Up To 10 GB</p> </CardContent> </Div> <CardButton secondary>LEARN MORE</CardButton> </Div> </Card> </CardWrapper> </> ); }
在这里,我们创建了另外两个卡片组件,使用 styled-components 添加我们自己的自定义组件,并使用我们上面定义的样式对象来包装我们的 Grommet 组件并改进样式。
我们最终的价格卡应用程序应如下图所示。
在生产中使用 Grommet(建筑清单应用程序)
要查看在另一个应用程序中使用 Grommet 的示例,我们将构建一个简单的应用程序,允许用户添加、查看和删除列表项。 我们将使用内置的 React Context API 来管理应用程序的状态,使用 Grommet 来管理我们的 UI 组件和 styled-components 来设置应用程序的样式。
同样,让我们使用下面的命令初始化一个反应应用程序。
create-react-app list-app
cd 进入项目目录
cd list-app
yarn add grommet grommet-controls grommet-icons styled-components
在上面的代码块中,我们安装了:
grommet | 我们的 UI 组件库 |
grommet-controls , grommet-icons | 我们需要安装以使用 Grommet 的图标和控件包 |
styled-components | 用于使用标记文字来设置反应组件和索环的样式 |
构建应用程序上下文
在应用程序中,我们需要在多个组件之间共享用户数据,以实现我们将使用 Context API。 有了这个,我们可以创建一个 App Context 来保存我们的应用程序的列表和逻辑。 您可以查看这篇文章以了解有关 Context API 的更多信息。
要创建我们的应用上下文,首先在应用程序的src
目录中创建一个名为context
的文件夹,接下来创建一个名为AppContext.js
的文件,这将是我们所有应用上下文的文件,让我们在下面的代码块中执行此操作:
import React, { createContext, useState } from 'react'; export const Context = createContext(); const AppContext = ({children}) => { const [lists, setLists] = useState([]); const removeList = item => { let newLists = [...lists]; lists.map((list, id) => { return list === item && newLists.splice(id, 1); }); setLists(newLists); }
在上面的代码块中,我们从 React 中导入了上下文 API 钩子createContext
和useState
钩子,使用useState
组件,我们为我们的应用程序创建了一个中央状态,这样做是为了让该组件可以充当其他的上下文提供者我们应用程序中的组件。 接下来,我们创建了一个名为removeList
的新变量,它接受一个项目作为参数,使用扩展运算符我们正在传播状态中的内容并拼接出与我们要删除的项目相等的对象。
接下来,我们将使用上面的逻辑在我们的应用程序中创建用于添加和删除列表项的方法,我们在下面的代码块中执行此操作:
return ( <Context.Provider value={{ lists, addToLists: (newItem) => setLists([...lists, newItem]), deleteFromList: (item) => removeList(item) }}> {children} </Context.Provider> ) } export default AppContext;
在这里,我们返回Context.Provider
并接受 children 道具,这样做是为了让其他组件能够访问我们在 value 道具中传递的属性,我们初始化了lists
对象以接收我们的列表, addToList
方法接受newItem
参数以将新列表添加到我们的应用程序状态,而deleteFromList
从列表存储中删除或删除项目。
构建列表组件
在本节中,我们将使用 Grommet 为我们的 UI 组件和 styled-components 构建我们的 List 组件以设置我们 UI 的某些部分的样式。 首先,在我们的应用程序src
目录中创建一个 components 文件夹,然后在 components 文件夹中,创建一个新文件List.js
并在其中编写以下代码。
import React from "react"; import styled from "styled-components"; import { Card, CardBody, Box, Text, Button } from "grommet"; function List(props) { return ( <StyledDiv> <Card> <CardBody className="card_body"> <Box direction="row" className="item_box"> <Text className="text">{props.list}</Text> <Box className="button_box"> <Button onClick={props.deleteList.bind(this, props.list)} className="button" > Delete </Button> </Box> </Box> </CardBody> </Card> </StyledDiv> ); } export default List;
在上面的代码中,我们首先从 grommet 中导入了 Card、CardBody、Box、Text 和 Button 组件,接下来我们创建了一个 List 组件来接收道具,使用 Grommet 组件我们创建了一个带有删除按钮的卡片组件,该按钮将自动添加到一个列表。 接下来是在下面为我们的组件设置样式:
const StyledDiv = styled.div` .button { background-color: #8b0000; color: white; padding: 10px; border-radius: 5px; } .card_body { padding: 20px; margin-top: 20px; } .item_box { justify-content: space-between; } .text { margin-top: auto; margin-bottom: auto; } `;
完成上述操作后,我们的组件应如下图所示。
构建列表显示组件
该组件显示我们添加的所有列表,并在添加新列表时自动生成一个删除按钮。
import React from "react"; import List from "./List"; import { Context } from '../context/AppContext'; function ListDisplay() { return ( <Context.Consumer> {(context) => ( <div className="container"> {context.lists.length ? context.lists.map((list, id) => ( <List key={id} list={list} deleteList={context.deleteFromList} /> )) : null } </div> )} </Context.Consumer> ); } export default ListDisplay;
在这个组件中,我们创建了一个ListDisplay
函数,并使用appContext
组件中的Context.Consumer
将其包装起来,接下来使用div
作为容器标签,我们从应用上下文中解构了list
和deleteList
方法,通过这样做我们可以将它们作为道具传递。 接下来,我们映射lists
以返回一个新列表,我们可以通过将返回的对象作为道具传递给List
组件来构建单个列表。
添加列表后,我们的组件应如下所示:
导航栏组件
这个组件将是我们应用程序的主体,在这里我们将使用Context.Consumer
来包裹我们的组件,并且与我们的其他组件类似,我们将使用样式化组件进行样式化。 让我们在下面构建这个组件。
import React, { useState } from "react"; import { Heading, Form, TextInput, Button } from "grommet"; import styled from "styled-components"; import { Context } from '../context/AppContext'; function Navbar() { const [value, setValue] = useState(""); return ( <Context.Consumer> {store => ( <StyledDiv className="container"> <Heading className="title">Grommet List App</Heading> <Form onSubmit={() => store.addToLists(value)} className="form-group"> <TextInput className="form" value={value} type="text" onChange={(e) => setValue(e.target.value)} placeholder="Enter item" /> <Button type='submit' className="button">Add to List</Button> </Form> </StyledDiv> )} </Context.Consumer> ); } const StyledDiv = styled.div` .button { margin-top: 10px; background-color: purple; color: white; padding: 10px; border-radius: 5px; } `; export default Navbar;
首先,为了访问应用程序上下文提供程序中的属性,我们将组件包装在Context.Consumer
组件中。 接下来,我们从 Grommet 添加了一个Heading
标签,然后我们使用addToList
方法创建了一个用于添加列表的输入表单,该方法接受一个值参数(在我们的例子中,该值是用户的输入)。 最后但同样重要的是,我们添加了一个提交按钮来处理表单提交。
正确完成后,我们的应用程序应如下所示:
结论
在本文中,我们了解了 Grommet,这是一个考虑到响应性和可访问性的组件库。 我们还完成了使用 Grommet 和列表应用程序创建定价组件应用程序的过程。 使用 Grommet 为您的组件和您的下一个 React 应用程序的 UI 需求带来乐趣。 Grommet 列表应用程序的代码可以在 Codesandbox 上找到,定价组件可以在这里找到。
资源
- 索环文档
- 索环简介
- React 的 Context API 简介