时间处理
不少博客都会在文章列表界面仅显示文章发布距今的时间(如下图),之前我们是粗暴地将后台传回的ISO 8601
格式的时间字符串显示出来,现在我们来处理一下。
首先让我们看看后台的数据经rest_framework
序列化后是什么样子:2020-04-05T11:10:56.880622+08:00
,要得到这样带时区的时间,需要改一下Django
设置,找到backend/backend/settings.py
,找到以下两个变量并修改:
# 顺便可以把语言设置也改了
LANGUAGE_CODE = 'zh-hans'
# 时区为亚洲上海
TIME_ZONE = 'Asia/Shanghai'
这里我们可以使用moment.js
来处理时间,现在来到前端部分,打开react_drf/frontend
目录,使用yarn
安装依赖,运行命令yarn add moment
。为了直接看到效果,别忘了把前后端两个程序都启动起来。现在来修改frontend/src/ArticleList.js
:
import React, {Component} from "react";
import moment from 'moment';
import momentLocale from 'moment/locale/zh-cn';
// 引入moment.js并设置语言
moment.updateLocale('zh-cn', momentLocale);
......
render() {
return (
<div className="ArticleList">
{this.state.articleList.map(item =>
........
<em>创建时间:{moment(item.created).fromNow()}</em>
{' '}
<em>更新时间:{moment(item.updated).fromNow()}</em>
</p>
</div>
)}
</div>
);
}
现在打开浏览器浏览localhost:3000
,你就能看到和上面图中一样的效果了。
注意:在我们要实现的这个功能上使用moment是属于杀鸡用牛刀的,这里只是最近看到这个库所以尝试用一下。
注意到有一行{' '}
,其实就是用JSX
的方式,在渲染后的HTML
中加个空格。
条件渲染
之前我们自己定义的名为articleList
的数组对象现在还在代码中,但是事实上我们并不需要它,我们的文章数据是从后台API
中取出的。现在删去原本定义articleList
部分的代码,并在我们的类组件ArticleList的构造函数
中修改以下部分:
constructor(props) {
super(props);
this.state = {
// 将state中的内容改完空数组
articleList: [],
};
}
.......
现在来关注一个组件中的render
函数:
render() {
const {articleList} = this.state;
......
}
增加这一行代码,从this.state
对象中直接取出articleList
,这样之前JSX
中的this.state.articleList
就都可以直接简写为articleList
了。目前我们在本地环境中,获取API非常快速,并且数据量也很少,那么如果在网络不好的情况下,后台的数据还没有取到,我们的页面当然不能一片空白吧?
修改render
函数的返回值部分如下:
return (
(Array.isArray(articleList) && articleList.length === 0)
?
<p>加载中...</p>
:
<div className="ArticleList">
{articleList.map(item =>
<div key={item.id}>
<h4>{item.title}</h4>
<p>
<strong>{item.body}</strong>
<br/>
<em>创建时间:{moment(item.created).fromNow()}</em>
{' '}
<em>更新时间:{moment(item.updated).fromNow()}</em>
</p>
</div>
)}
</div>
);
这里我们在JSX
中使用了三元运算符,代码很简单,只是当articleList
数组不为空时显示文章列表,否则渲染<p>加载中...</p>
。不过在JS
中判断一个数组是否为空是有些坑存在的,例如arr == []
或arr === []
都只会返回false
。(PS:忍不住又想吐槽JS了。。。
现在打开浏览器刷新,不过由于这里获取到数据很快,所以会“加载中”的字样会一闪而过,可以将整个componentDidMount
函数注释掉看看效果。
这就是React
中的条件渲染了,可以根据情况来决定组件的渲染,目前我们的页面还非常简单,等以后我们添加了导航栏、侧边栏等元素时,你当然不希望因为文章数据还没取到而使得页面空空如也吧。
小练习:试着在网络出错的情况下,让组件渲染出与平时不同的内容。
提示
对代码做以下修改,将fetch
捕获到的错误,设置到this.state
中。完成练习后,暂停Django
的运行,验证你做的是否正确吧。
constructor(props) {
super(props);
this.state = {
articleList: [],
error: null,
};
}
componentDidMount() {
fetch('/articles/')
......
.catch(e => this.setState({error: e}));
}
添加样式
可能你已经发现了,frontend/src
目录下,除了后缀名为js
的文件,还有后缀为css
的同名文件,打开App.js
看一看(如果你还没有删除它),还能发现import './App.css';
这一行代码。
现在让我们也来写一个ArticleList.css
:
.ArticleList {
text-align: center;
}
只是个文本居中显示,注意到我们已经在组件render
函数的JSX
中定义了div
元素的className
。现在只要在App.js
中引入样式文件就行,在代码顶部添加import './ArticleList.css';
。现在可以在页面中看到文字居中显示了。
也可以在JSX
中直接设定样式,例如:
<h4 style={{ color: "red" }}>{item.title}</h4>
现在可以看到标题变成了红色。
欢迎关注我的公众号“公子政的宅日常”,原创技术文章第一时间推送。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。