用 React 构建可复用的设计系统(一)

简介: 用 React 构建可复用的设计系统

React 让 web 开发简化了很多。原则上 React 基于组件的模式让代码分解和复用变得更加容易。 然而,开发者并不总是清楚如何跨项目分享他们的组件。在这片文章中,我会展示几种可用的方法。

React 让书写漂亮,并富有表达力的代码更加容易。然而,如果组件不能很好的复用,随着时间的推移代码变得更加零散和更加难以维护。 我曾经看到的代码库中,同样的 UI 有十几种不同的实现!另外一个问题,开发者通常会把 UI 和业务代码耦合在一起,当 UI 需要改变时就变的很困难。

今天,我们将会看到如何创建可共享的 UI 组件,如何构建贯穿整个应用的一致的设计语言。


开始


一开始你需要一个空的 React 项目。最快捷的方式就是 create-react-app,但是,还是需要设置一下 Sass。 我创建了一个应用框架,你可以在 GitHub 克隆它。你也可以在教程的代码仓中找到完整的项目(https://github.com/tutsplus/build-a-reusable-design-system-with-react)。

运行yarn-install 安装所有的依赖,然后通过 yarn start 启动应用。

所有的视觉组件和相应的样式单独保存在 design_system 目录下。任何全局样式和变量保存在 src/styles

04ef8801ce0b5cb368f50e8c30ef9642_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


设置设计的基准


最近一次被设计同行鄙视是什么时候,padding 半个像素的错误,或者不能区分各个灰色色调的区别?(我被告知,#eee#efefef 有不同,我打算在一天内找出来)

构建 UI 库其中之一的目的是为了提升设计和开发团队的关系。前端开发者和 API 设计者已经可以很好的沟通并构建很好的 API 协议。 但是,由于某些原因,在跟设计团队沟通时总是逃避。想象一下,对于一个 UI 元素只能存在有限的几个状态。 例如,如果,我们设计一个标题组件,它可以是 h1h6 任何一个标签,可以是粗体、斜体或者有下划线。这个实现起来应该很直接。


网格系统


在着手构建任何设计项目时首先考虑的是需要理解网格是如何构建的。对于很多应用来说,这很随意。这会导致间距系统非常零散,并且开发者很难确定该使用那个间距。 因此需要确定一个合适的间距。当我第一次阅读 4px - 8px 网格系统时就爱上了它。遵守这一规则会简化我们样式的很多问题。

让我们在代码中先设置一个基本的网格系统。我们从设置布局的 app 组件开始。

//src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.scss';
import { Flex, Page, Box, BoxStyle } from './design_system/layouts/Layouts';
class App extends Component {
    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">
Build a design system with React</h1>
                </header>
                <Page>
                    <Flex lastElRight={true}>
                        <Box boxStyle={BoxStyle.doubleSpace} >
                            A simple flexbox
                        </Box>
                        <Box boxStyle={BoxStyle.doubleSpace} >Middle</Box>
                        <Box fullWidth={false}>and this goes to the right</Box>
                    </Flex>
                </Page>
            </div>
        );
    }
}
export default App;


接下来,我们定义了一些样式和包装组件。

//design-system/layouts/Layout.js
import React from 'react';
import './layout.scss';
export const BoxBorderStyle = {
    default: 'ds-box-border--default',
    light: 'ds-box-border--light',
    thick: 'ds-box-border--thick',
}
export const BoxStyle = {
    default: 'ds-box--default',
    doubleSpace: 'ds-box--double-space',
    noSpace: 'ds-box--no-space'
}
export const Page = ({children, fullWidth=true}) => {
    const classNames = `ds-page ${fullWidth ? 
'ds-page--fullwidth' : ''}`;
    return (<div className={classNames}>
        {children}
    </div>);
};
export const Flex = ({ children, lastElRight}) => {
    const classNames = `flex ${lastElRight ?
'flex-align-right' : ''}`;
    return (<div className={classNames}>
        {children}
    </div>);
};
export const Box = ({
children, borderStyle=BoxBorderStyle.default, boxStyle=
BoxStyle.default, fullWidth=true}) => {
    const classNames = `ds-box ${borderStyle} ${boxStyle} $
{fullWidth ?'ds-box--fullwidth' : ''}` ;
    return (<div className={classNames}>
        {children}
    </div>);
};

最后,我们将在 SCSS 中定义样式。

/*design-system/layouts/layout.scss */
@import '../../styles/variables.scss';
$base-padding: $base-px * 2;
.flex {
    display: flex;
&.flex-align-right > div:last-child {
        margin-left: auto;
    }
}
.ds-page {
    border: 0px solid #333;
    border-left-width: 1px;
    border-right-width: 1px;
&:not(.ds-page--fullwidth){
        margin: 0 auto;
        max-width: 960px;
    }
&.ds-page--fullwidth {
        max-width: 100%;
        margin: 0 $base-px * 10;
    }
}
.ds-box {
    border-color: #f9f9f9;
    border-style: solid;
    text-align: left;
&.ds-box--fullwidth {
        width: 100%;
    }
&.ds-box-border--light {
        border: 1px;
    }
&.ds-box-border--thick {
        border-width: $base-px;
    }
&.ds-box--default {
        padding: $base-padding;
    }
&.ds-box--double-space {
        padding: $base-padding * 2;
    }
&.ds-box--default--no-space {
        padding: 0;
    }
}

有很多在这没有展示。让我们从头开始。variables.scss 定义了全局的变量,比如:颜色和网格的设置。由于我们使用了 4px-8px 网格,我们将用 4px 做为基础值。 父组件是 Page,它控制着页面的文档流。层级最低元素是 Box,它定义了内容如何在页面上渲染。它本身就是一个 div,并在自身的上下文中渲染自己。

现在,我们需要一个 Container 组件,它包含多个 div。我们选择 flex-box,所以组件命名为 Flex


定义 Type 系统


Type 系统是任何应用的关键组件。通常,我们会定义一个基本的全局样式,在需要的情况下复写它。 这经常会导致设计不一致。让我们看看如何通过设计库来轻松的解决这个问题。

首先,我们会定义一些样式常量和一个 class 容器。

// design-system/type/Type.js
import React, { Component } from 'react';
import './type.scss';
export const TextSize = {
    default: 'ds-text-size--default',
    sm: 'ds-text-size--sm',
    lg: 'ds-text-size--lg'
};
export const TextBold = {
    default: 'ds-text--default',
    semibold: 'ds-text--semibold',
    bold: 'ds-text--bold'
};
export const Type = ({tag='span', size=TextSize.default, 
boldness=TextBold.default, children}) =>
 {
    const Tag = `${tag}`;
    const classNames = `ds-text ${size} ${boldness}`;
    return <Tag className={classNames}>
        {children}
        </Tag>
};

接下来,我们会为这些 text 元素定义样式。

/* design-system/type/type.scss*/
@import '../../styles/variables.scss';
$base-font: $base-px * 4;
.ds-text {
    line-height: 1.8em;
&.ds-text-size--default {
        font-size: $base-font;
    }
&.ds-text-size--sm {
        font-size: $base-font - $base-px;
    }
&.ds-text-size--lg {
        font-size: $base-font + $base-px;
    }
&strong, &.ds-text--semibold {
        font-weight: 600;
    }
&.ds-text--bold {
        font-weight: 700;
    }
}

这是一个简单的 Text 组件,它代表了 UI 的各个状态。我们可以进一步扩展这个功能来处理交互功能,比如:当文本被省略的时候现实一个 tooltip,或者为 email、time 渲染不同的样式等等。


目录
相关文章
|
11天前
|
移动开发 前端开发 JavaScript
构建高效跨平台移动应用:React Native入门指南
【8月更文挑战第47天】在移动开发领域,React Native凭借其跨平台特性和高效的开发模式赢得了开发者的青睐。本文将通过一个简易的待办事项应用实例,带领读者快速入门React Native,并展示如何利用JavaScript和React框架构建具有原生性能的应用。我们将探讨环境配置、界面布局、状态管理和数据流,以及如何打包和发布您的应用。准备好,让我们开始React Native之旅!
52 20
|
30天前
|
前端开发 JavaScript API
构建高效Web应用:React与Node.js的完美结合
【8月更文挑战第29天】在当今快速变化的软件开发领域,构建高性能、可扩展的Web应用成为开发者的首要任务。本文将深入探讨如何利用React和Node.js这两大技术栈,打造一个高效且响应迅速的现代Web应用。从前端的用户界面设计到后端的服务逻辑处理,我们将一步步分析这两种技术如何协同工作,提升应用性能,并确保用户体验的流畅性。通过实际代码示例和架构设计的解析,本篇文章旨在为读者提供一套清晰的指南,帮助他们在项目开发中做出更明智的技术选择。
|
29天前
|
前端开发 应用服务中间件 nginx
[译] 面向 React 和 Nginx 的 Docker 多阶段构建
[译] 面向 React 和 Nginx 的 Docker 多阶段构建
[译] 面向 React 和 Nginx 的 Docker 多阶段构建
|
1月前
|
存储 前端开发 JavaScript
React Hooks的魔法:如何在组件世界里施展响应式与复用的魔法
【8月更文挑战第27天】React Hooks 是自 React 16.8 起新增的功能,支持开发者在无需类组件的情况下利用 React 的状态管理和特性。本文通过实例展示了多种核心 Hooks 的使用方法:`useState` 用于实现响应式状态管理;`useEffect` 处理副作用操作,如数据获取等;`useMemo` 和 `useCallback` 有助于性能优化;`useRef` 则提供对 DOM 的直接引用。
31 2
|
27天前
|
移动开发 前端开发 JavaScript
构建高效跨平台移动应用:React Native入门指南
【8月更文挑战第31天】 在移动开发领域,React Native凭借其跨平台特性和高效的开发模式赢得了开发者的青睐。本文将通过一个简易的待办事项应用实例,带领读者快速入门React Native,并展示如何利用JavaScript和React框架构建具有原生性能的应用。我们将探讨环境配置、界面布局、状态管理和数据流,以及如何打包和发布您的应用。准备好,让我们开始React Native之旅!
|
27天前
|
前端开发 Java UED
瞬间变身高手!JSF 与 Ajax 强强联手,打造极致用户体验的富客户端应用,让你的应用焕然一新!
【8月更文挑战第31天】JavaServer Faces (JSF) 是 Java EE 标准的一部分,常用于构建企业级 Web 应用。传统 JSF 应用采用全页面刷新方式,可能影响用户体验。通过集成 Ajax 技术,可以显著提升应用的响应速度和交互性。本文详细介绍如何在 JSF 应用中使用 Ajax 构建富客户端应用,并通过具体示例展示 Ajax 在 JSF 中的应用。首先,确保安装 JDK 和支持 Java EE 的应用服务器(如 Apache Tomcat 或 WildFly)。
31 0
|
27天前
|
前端开发 JavaScript UED
🎬JSF 与 Ajax:打造瞬间响应的魔法界面!🚀 用户输入即刻,数据交互如梦幻泡影般呈现!
【8月更文挑战第31天】在现代Web应用中,异步数据交互是提升用户体验的关键。JavaServer Faces (JSF) 作为标准Java Web框架,结合Ajax技术,可轻松实现页面异步更新与数据交互。本文通过示例代码介绍如何在JSF中使用Ajax组件(如`f:ajax`)及后端处理方法实现异步功能,并结合JavaScript处理复杂交互,帮助开发者提升Web应用体验。
33 0
|
27天前
|
前端开发 JavaScript Android开发
React Native 快速入门简直太棒啦!构建跨平台移动应用的捷径,带你开启高效开发之旅!
【8月更文挑战第31天】React Native凭借其跨平台特性、丰富的生态系统及优异性能,成为移动应用开发的热门选择。它允许使用JavaScript和React语法编写一次代码即可在iOS和Android上运行,显著提升开发效率。此外,基于React框架的组件化开发模式使得代码更加易于维护与复用,加之活跃的社区支持与第三方库资源,加速了应用开发流程。尽管作为跨平台框架,React Native在性能上却不输原生应用,支持原生代码优化以实现高效渲染与功能定制。对于开发者而言,React Native简化了移动应用开发流程,是快速构建高质量应用的理想之选。
33 0
|
2月前
|
存储 前端开发 JavaScript
深入浅出React框架:构建高效组件化网页的实战指南
【7月更文挑战第9天】在当今快速发展的前端技术领域,React凭借其强大的组件化思想、高效的虚拟DOM以及丰富的生态系统,成为了构建动态用户界面的首选框架之一。本文将带你深入浅出地探索React的核心概念,并通过实战示例,展示如何利用React构建高效、可维护的组件化网页。
89 8
|
3月前
|
前端开发 JavaScript Linux
分离前后端react和django3构建的应用
【6月更文挑战第4天】在本文中,我们介绍了如何设置React前端并连接到Django后端。并讨论了前后端分离的好处,并计划扩展API以支持更多HTTP操作和用户身份验证功能。
93 5
分离前后端react和django3构建的应用

热门文章

最新文章