沉着前进 2019-07-01
- 来源 | 愿码(ChainDesk.CN)内容编辑
- 愿码Slogan | 连接每个程序员的故事
- 网站 | http://chaindesk.cn
- 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。
- 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
- 免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码
本文阅读时长:13min
以前使用Create React App,你实际上没有很多选项可以直观地清理。经常处于随机级联样式表 (CSS)项目维护者的心血来潮之中,并且试图让项目编译过程中涉及的其他库,框架或预处理器经常成为一场噩梦。
Create React App上下文中的预处理器基本上是构建过程中的一个步骤。在这种情况下,我们讨论的是采用某些样式代码(CSS或其他格式)的东西,将其编译为基本CSS,并将其添加到构建过程的输出中。
在本文的篇幅中,我们将介绍涵盖与样式相关的功能的各种材料,并突出显示在我看来,Create React App中最好的新功能之一:支持CSS模块和SASS。
CSS模块能够以防止引入全局重叠命名空间的方式模块化你所导入的任何CSS代码,尽管最终结果仍然只是一个巨大的CSS文件。
让我们首先清理一下我们项目中的目录结构。我们要做的就是将每个具有CSS和JavaScript代码的组件分离到自己的文件夹中。先来创建NewTodo,Todo,App,TodoList,和Divider文件夹,并将它们所有相关的代码放在其中的每一个文件夹中。
我们还需要在每个被调用的目录中创建一个新文件,该文件index.js只负责导入和导出相应的组件。例如,App索引文件(src/App/index.js)将如下所示:
import App from "./App"; export default App;
Todo (src/Todo/index.js)的新索引文件 如下所示:
import Todo from "./Todo"; export default Todo;
你可以根据此模式猜测索引文件的内容NewTodo,TodoList以及它们的Divider外观。
接下来,我们需要更改引用这些文件的每个位置,以便更轻松地导入所有这些文件。不幸的是,这将是一些繁琐的工作,但我们需要做同样的事情,以确保我们不会破坏过程中的任何事情。
首先,在中src/App/App.js,将TodoList import 组件更改为以下内容:
import TodoList from "../TodoList";
我们不需要做任何事情,Divider因为它是一个没有导入的组件。NewTodo 并且Todo 是类似的类型,所以我们也可以跳过它们。src/TodoList/TodoList.js另一方面,我们需要处理很多事情,因为它是我们最高级别的组件之一并且进口很多:
import Todo from "../Todo"; import NewTodo from "../NewTodo"; import Divider from "../Divider";
但那还不是全部。我们的测试文件src/TodoList/TodoList.test.js也需要修改为包含文件的这些新路径,否则我们的测试将失败!我们需要几乎与之前相同的导入列表:
import TodoList from "./TodoList"; import NewTodo from "../NewTodo"; import Todo from "../Todo";
当你重新加载你的应用程序时,你的代码应该仍然正常工作,测试应该全部通过,一切都应该干净利落!我们的完整项目结构现在应如下所示:
src/ App/ App.css App.js App.test.js index.js Divider/ Divider.css Divider.js index.js NewTodo/ NewTodo.css NewTodo.js NewTodo.test.js index.js Todo/ Todo.css Todo.js Todo.test.js index.js TodoList/ TodoList.css TodoList.js TodoList.test.js index.js index.css index.js setupTests.js ... etc ...
如果我们想使用CSS模块,我们需要遵循一些简单的指南。首先,我们需要命名我们的文件[whatever].module.css,而不是[whatever].css。接下来我们需要做的是确保我们的样式简单命名并且易于引用。让我们首先遵循这些约定并将我们的CSS文件重命名为Todoas src/Todo/Todo.module.css,然后我们将稍微改变一下内容:
.todo { border: 2px solid black; text-align: center; background: #f5f5f5; color: #333; margin: 20px; padding: 20px; } .done { background: #f5a5a5; }
接下来,我们将开放src/Todo/Todo.js以利用CSS模块。我们在我们的Todo组件中创建了一个辅助函数cssClasses(),它返回我们应该在组件中使用的样式,并且我们不需要进行更改以使所有工作与之前完全相同。我们还需要import在顶部更改我们的语句,因为我们重命名了文件并且正在改变我们的CSS加载到代码中的方式!看看以下内容:
import styles from "./Todo.module.css";
这使我们的代码可以Todo.module.css通过引用它们来利用定义的任何类名styles.[className]。例如,在前一个文件中,我们定义了两个CSS类名:todo和done,所以我们现在可以通过styles.Todo和在组件中引用它们styles.done。我们需要更改cssClasses()函数才能使用它,所以让我们现在进行那些确切的更改。在src/Todo/Todo.js,我们的cssClasses()功能现在应该如下所示:
cssClasses() { let classes = [styles.todo]; if (this.state.done) { classes = [...classes, styles.done]; } return classes.join(' '); }
保存并重新加载,我们的应用程序应该恢复正常!接下来,让我们更改组件hr内部的标签todo以拥有自己的样式和效果。返回src/Todo/Todo.module.css并为我们的hr标签添加以下块,我们将给出一个新类redDivider:
.redDivider { border: 2px solid red; }
最后,返回我们的render()函数src/Todo/Todo.js,并将render()函数的hr标记包含更改保存并重新加载,现在我们应该完全划分CSS代码而不必担心冲突和全局命名空间!这是输出的样子:
这并不是CSS模块给我们的全部,尽管它肯定是CSS模块的重要组成部分之一,我们立即得到并毫不费力。我们还获得了CSS可组合性,它能够从其他类继承CSS类,无论它们是否在主文件中。当您设置更复杂的嵌套组件时,这可能非常有用,这些组件都需要处理略有不同的样式表,但彼此之间并没有太大的不同。
假设我们希望能够将某些组件标记为关键组件而不仅仅是常规Todos。我们不想对组件做太多改变; 我们希望它继承与所有其他Todos相同的基本规则。我们需要设置一些代码来实现这一目标。回到后面src/Todo/Todo.js,我们将进行一些修改以允许一个名为的新状态属性critical。我们将从constructor 组件开始,我们将添加新state属性和bind 函数标记:
constructor(props) { super(props); this.state = { done: false, critical: false };
this.markAsDone = this.markAsDone.bind(this); this.removeTodo = this.removeTodo.bind(this); this.markCritical = this.markCritical.bind(this); }
我们在critical属性中添加一个新属性,state 并将其设置为默认值false。然后我们还引用了一个函数(我们还没有编写)markCritical,并且我们绑定了this,因为我们稍后将在事件处理程序中使用它。接下来,我们将解决这个问题markCritical():
markCritical() { this.setState({ critical: true }); }
我们还需要修改我们的cssClasses()函数,以便它可以对这个新state属性做出反应。为了演示CSS模块的可组合性功能,我们将其设置classes为原来是一个空数组,然后第一个项目变为critical或todo,取决于项目是否标记为critical:
cssClasses() { let classes = []; if (this.state.critical) { classes = [styles.critical]; } else { classes = [styles.todo]; } if (this.state.done) { classes = [...classes, styles.done]; } return classes.join(' '); }
最后,在我们的render函数中,我们将创建button 标记以将项目标记为critical:
render() { return ( {this.props.description} Mark as Done Remove Me Mark as Critical ); }
我们还没有完成,尽管我们至少有90%的方式。我们还想回到src/Todo/Todo.module.css并为critical类名添加一个新块,我们也将使用我们的可组合属性:
.critical { composes: todo; border: 4px dashed red; }
要使用合成,您需要做的就是添加一个新的CSS属性,composes并为其指定一个您希望它组成的类名(或多个类名)。在这种情况下,撰写是一种奇特的方式,它表示它继承了其他类名的行为,并允许您覆盖其他类名。在前面的例子中,我们说的critical是一个CSS模块类,它由一个todo 模型作为基础,并添加border 一个大的红色虚线的组件,因为,我们只是说这意味着它是关键的。
像往常一样保存并重新加载,您应该能够将项目标记为标记为完成,标记为严重或两者,或通过单击删除我删除它们,如以下屏幕截图所示:
这就是我们对CSS模块的简要介绍!在继续之前,您还需要通过在屏幕中点击U来快速更新测试快照yarn test。
SASS本质上是具有扩展功能支持的CSS。当我在这里说扩展功能支持时,我的意思是它!SASS支持以下功能集,CSS中缺少这些功能集:
· 变量
· 嵌套
· 部分CSS文件
· 导入支持
· 混入
· 扩展和继承
· 运算符和计算
好消息是,在Create React App项目中获得SASS支持非常简单。我们首先需要通过yarn或安装它npm。
$ yarn add node-sass
我们将看到它的大量输出,但假设没有错误并且一切顺利,我们应该能够重新启动我们的开发服务器并开始使用一些SASS。让我们创建一个更通用的实用程序SASS文件,它将负责存储我们想要在整个应用程序中使用的标准化颜色,以及存储整齐渐变hr模式的东西,以防我们想在其他地方使用它。
我们还将更改我们正在使用的一些颜色,以便有一些红色,绿色和蓝色,这取决于项目是分别是关键,完成还是两者都不是。此外,我们需要稍微改变我们的项目,并添加一个新文件,以获得一些共享样式和颜色的概念。那么,让我们开始吧:
$todo-critical: #f5a5a5; $todo-normal: #a5a5f5; $todo-complete: #a5f5a5; $fancy-gradient: linear-gradient( to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0) );
import "./Divider.scss";
@import "../shared"; hr { border: 0; height: 1px; background-image: $fancy-gradient; }
因此,我们在新的共享SASS文件中导入src/,然后该background-image值只引用$fancy-gradient我们创建的变量,这意味着我们现在可以在需要时重新创建那个花哨的渐变而无需反复重写它。
好消息是,在Create React App中将SASS引入CSS模块基本上并不复杂。事实上,这些步骤是相同的!所以,如果我们想要开始混合这两者,我们需要做的就是重命名一些文件并改变我们的导入处理方式。让我们看看这个行动:
import styles from "./Todo.module.scss";
@import '../shared';
.todo { border: 2px solid black; text-align: center; background: $todo-normal; color: #333; margin: 20px; padding: 20px; }
.done { background: $todo-complete; } .hr { border: 2px solid red; } .critical { composes: todo; background: $todo-critical; }
现在,我们在Create React App项目中很好地集成了CSS模块和SASS,而无需安装单个新依赖项。我们让他们一起玩得很好 ,这是一个更大的成就!