e
给React应用加点样式
我们目前的应用的外观是相当简陋的。在练习0.2中,任务是通过Mozilla的CSS教程。
在我们进入下一部分之前,让我们看一下如何在React应用中添加样式。有几种不同的方法,我们将在后面看一下其他的方法。首先,我们将以老式的方式向我们的应用添加CSS;在一个文件中,不使用CSS预处理器(尽管这并不完全正确,我们将在后面学习)。
让我们在src目录下添加一个新的index.css文件,然后通过在index.js文件中导入它来添加到应用。
import './index.css'
让我们在index.css文件中添加以下CSS规则。
h1 {
color: green;
}
注意:当文件index.css的内容发生变化时,React可能不会自动注意到,所以你可能需要刷新浏览器才能看到你的变化!
CSS规则由选择器和声明组成。选择器定义了该规则应该应用于哪些元素。上面的选择器是h1,它将匹配我们应用中所有的h1头标签。
该声明将color属性设置为green值。
一条CSS规则可以包含任意数量的属性。让我们修改前面的规则,通过定义字体样式为italic,使文字变成草书。
h1 {
color: green;
font-style: italic;}
通过使用不同类型的CSS选择器,有许多匹配元素的方法。
如果我们想用我们的样式针对,比方说,每一个笔记,我们可以使用选择器li,因为所有的笔记都被包裹在li标签里。
const Note = ({ note, toggleImportance }) => {
const label = note.important
? 'make not important'
: 'make important';
return (
<li>
{note.content}
<button onClick={toggleImportance}>{label}</button>
</li>
)
}
让我们在我们的样式表中加入以下规则(因为我对优雅的网页设计的知识接近于零,所以这些样式并没有什么意义)。
li {
color: grey;
padding-top: 3px;
font-size: 15px;
}
使用元素类型来定义CSS规则是有点问题的。如果我们的应用包含其他的li标签,同样的样式规则也会应用于它们。
如果我们想把我们的样式专门应用于笔记,那么最好使用类选择器。
在常规HTML中,类被定义为class属性的值。
<li class="note">some text...</li>
在React中,我们必须使用className属性而不是class属性。考虑到这一点,让我们对我们的Note组件做如下修改。
const Note = ({ note, toggleImportance }) => {
const label = note.important
? 'make not important'
: 'make important';
return (
<li className='note'> {note.content}
<button onClick={toggleImportance}>{label}</button>
</li>
)
}
类选择器是用.classname语法定义的。
.note {
color: grey;
padding-top: 5px;
font-size: 15px;
}
如果你现在在应用中添加其他li元素,它们将不会受到上述样式规则的影响。
Improved error message
我们之前实现了当用户试图用alert方法切换已删除笔记的重要性时显示的错误信息。让我们把这个错误信息实现为它自己的React组件。
这个组件很简单。
const Notification = ({ message }) => {
if (message === null) {
return null
}
return (
<div className='error'>
{message}
</div>
)
}
如果messageprop的值是null,那么就不会有任何东西渲染在屏幕上,而在其他情况下,信息会渲染在一个div元素中。
让我们在App组件中添加一个新的状态,叫做errorMessage。让我们用一些错误信息来初始化它,这样我们就可以立即测试我们的组件。
const App = () => {
const [notes, setNotes] = useState([])
const [newNote, setNewNote] = useState('')
const [showAll, setShowAll] = useState(true)
const [errorMessage, setErrorMessage] = useState('some error happened...')
// ...
return (
<div>
<h1>Notes</h1>
<Notification message={errorMessage} /> <div>
<button onClick={() => setShowAll(!showAll)}>
show {showAll ? 'important' : 'all' }
</button>
</div>
// ...
</div>
)
}
然后让我们添加一个适合错误信息的样式规则。
.error {
color: red;
background: lightgrey;
font-size: 20px;
border-style: solid;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
现在我们准备添加显示错误信息的逻辑。让我们以下列方式改变toggleImportanceOf函数。
const toggleImportanceOf = id => {
const note = notes.find(n => n.id === id)
const changedNote = { ...note, important: !note.important }
noteService
.update(changedNote).then(returnedNote => {
setNotes(notes.map(note => note.id !== id ? note : returnedNote))
})
.catch(error => {
setErrorMessage( `Note '${note.content}' was already removed from server` ) setTimeout(() => { setErrorMessage(null) }, 5000) setNotes(notes.filter(n => n.id !== id))
})
}
当错误发生时,我们在errorMessage状态中添加一个描述性的错误信息。同时,我们启动一个定时器,在五秒后将errorMessage状态设置为null。
结果看起来是这样的。
我们应用当前状态的代码可以在GitHub上的part2-7分支找到。
Inline styles
React也可以在代码中直接编写样式,即所谓的内联样式。
定义内联样式的想法非常简单。任何React组件或元素都可以通过style属性作为JavaScript对象提供一组CSS属性。
CSS规则在JavaScript中的定义与普通的CSS文件略有不同。比方说,我们想给某个元素加上绿色和16像素的斜体字。在CSS中,它看起来是这样的。
{
color: green;
font-style: italic;
font-size: 16px;
}
但是作为React的内联样式对象,它会如下所示:
{
color: 'green',
fontStyle: 'italic',
fontSize: 16
}
每个CSS属性都被定义为JavaScript对象的一个独立属性。像素的数字值可以简单地定义为整数。与普通的CSS相比,其中一个主要区别是,连字符(kebab case)的CSS属性是用camelCase写的。
接下来,我们可以通过创建一个Footer组件并为其定义以下内联样式,为我们的应用添加一个 "底层块"。
const Footer = () => { const footerStyle = { color: 'green', fontStyle: 'italic', fontSize: 16 } return ( <div style={footerStyle}> <br /> <em>Note app, Department of Computer Science, University of Helsinki 2022</em> </div> )}
const App = () => {
// ...
return (
<div>
<h1>Notes</h1>
<Notification message={errorMessage} />
// ...
<Footer /> </div>
)
}
内联样式有某些限制。例如,所谓的伪类不能被直接使用。
内联样式和其他一些为React组件添加样式的方式完全违背了旧的惯例。传统上,人们认为最好的做法是将CSS与内容(HTML)和功能(JavaScript)完全分开。根据这个老的思想流派,目标是将CSS、HTML和JavaScript写进各自的文件。
事实上,React的哲学是与此截然相反的。由于将CSS、HTML和JavaScript分离到不同的文件中,在大型应用中似乎不能很好地扩展,React将应用的划分建立在其逻辑功能实体的基础上。
构成应用功能实体的结构单元是React组件。一个React组件定义了构造内容的HTML,决定功能的JavaScript函数,以及组件的样式;所有这些都在一个地方。这是为了创建尽可能独立和可重复使用的单个组件。
我们应用的最终版本的代码可以在GitHub的part2-8分支中找到。