如何使用 React 创建时间轴组件
最近我一直在为我的网站制作一个新页面。我想用一个时间轴来展示我多年来的一些职业成就。
我这么做有几个原因:
- 未来的某一天,我会回首往事,感叹:“哇……我还记得我实现那个目标的那一天!实现那个目标我有多开心啊!” 成功是一段旅程,而非终点,我想写下一路走来我实现的每一个目标。
- 它可能会吸引更多的客户(我们拭目以待吧😄)
- 在我看来,这是一个与众不同的作品集。或许是一个独一无二的作品集?😜
尽管如此...我们现在就建造一些东西吧!
在上图中,你可以看到我们今天要用 React 构建的内容!在开始之前,让我们先分解一下需要采取的步骤:
- 创建
data
我们需要的 - 创建
TimelineItem
组件 - 每个单独的时间线条目 - 创建一个
Timeline
容器 - 它将接收data
并将其传递TimelineItem
给 - 为一切设计风格
创建数据
在实际创建 React 组件之前,我们需要确切地知道数据的外观,以便我们可以规划出 DOM 结构。
对于这个时间轴应用,我们需要一个对象数组timelineData
。我们将这个数组命名为: 。
让我们看看它看起来怎么样:
[
{
text: 'Wrote my first blog post ever on Medium',
date: 'March 03 2017',
category: {
tag: 'medium',
color: '#018f69'
},
link: {
url:
'https://medium.com/@popflorin1705/javascript-coding-challenge-1-6d9c712963d2',
text: 'Read more'
}
},
{
// Another object with data
}
];
这些属性很简单,对吧?我使用的数据和我的时间线页面类似,所以可以说它已经可以投入生产了!😆
接下来,我们将构建TimelineItem
组件。这将使用上面对象中的数据:
TimelineItem 组件
const TimelineItem = ({ data }) => (
<div className="timeline-item">
<div className="timeline-item-content">
<span className="tag" style={{ background: data.category.color }}>
{data.category.tag}
</span>
<time>{data.date}</time>
<p>{data.text}</p>
{data.link && (
<a
href={data.link.url}
target="_blank"
rel="noopener noreferrer"
>
{data.link.text}
</a>
)}
<span className="circle" />
</div>
</div>
);
我们有以下标签:
.timeline-item
div - 用作包装器。此 div 的宽度将是其父级宽度的一半(50%
),并且每个其他div 将使用选择器.timeline-item
放置在右侧:nth-child(odd)
.timeline-item-content
div - 另一个包装器(更多关于我们为什么需要它的信息请参见样式部分).tag
span - 此标签将根据类别具有自定义背景颜色- /和
time
date
text
link
- 我们需要检查是否link
提供了,因为我们可能并不总是想要一个.circle
span - 此标签将用于在中间线/条上放置一个圆圈
注意:当我们进入CSS /样式部分时,一切都会变得更有意义,但在此之前,让我们先创建Timeline
组件:
时间轴容器
这个组件基本上会map
覆盖整个数组,并为每个对象创建一个TimelineItem
组件。我们还添加了一个小检查,以确保数组中至少有一个元素:
import timelineData from '_path_to_file_';
const Timeline = () =>
timelineData.length > 0 && (
<div className="timeline-container">
{timelineData.map((data, idx) => (
<TimelineItem data={data} key={idx} />
))}
</div>
);
如上所述,这timelineData
是一个包含所有必需信息的对象数组。在我的例子中,我将这个数组存储在一个文件中,然后将其导入到这里。不过,您可以从自己的数据库或 API 端点获取它,这取决于您。
CSS
请注意,大多数包装器都是flexbox
容器,因为我们可以更轻松地调整它们的定位。让我们从.timeline-container
CSS 开始:
.timeline-container {
display: flex;
flex-direction: column;
position: relative;
margin: 40px 0;
}
.timeline-container::after {
background-color: #e17b77;
content: '';
position: absolute;
left: calc(50% - 2px);
width: 4px;
height: 100%;
}
我们使用::after
选择器在 的中间创建那条红线/条.timeline-container
。使用calc()2px
函数,我们可以从 中减去其大小的一半( ),从而将线条精确定位在中间50%
。我们需要这样做是因为默认情况下,该left
属性会根据元素的左边缘而不是中间位置来定位线条。
现在,让我们转到.timeline-item
包装器。
下面你可以看到它们在其父级()中如何定位的示例.timeline-container
。为了演示,我添加了一个边框来突出显示这些包装器:
如你所见,其他所有包装器都位于右侧,而内部包装器(.timeline-item-content
)占用的空间较少——p
大部分空间由其内部的标签提供。让我们看看它的 CSS:
.timeline-item {
display: flex;
justify-content: flex-end;
padding-right: 30px;
position: relative;
margin: 10px 0;
width: 50%;
}
.timeline-item:nth-child(odd) {
align-self: flex-end;
justify-content: flex-start;
padding-left: 30px;
padding-right: 0;
}
关键在于我们使用:nth-child(odd)
选择器并将align-self
属性设置为flex-end
:“尽可能向右走”!
因为这些包装器是50%
按宽度排列的,所以你可以看到其中两个占据了整个宽度。从现在开始,每次我们想在右侧设置不同的样式时,都必须使用这种方法。
接下来是.timeline-item-content
包装器:
.timeline-item-content {
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
border-radius: 5px;
background-color: #fff;
display: flex;
flex-direction: column;
align-items: flex-end;
padding: 15px;
position: relative;
width: 400px;
max-width: 70%;
text-align: right;
}
.timeline-item-content::after {
content: ' ';
background-color: #fff;
box-shadow: 1px -1px 1px rgba(0, 0, 0, 0.2);
position: absolute;
right: -7.5px;
top: calc(50% - 7.5px);
transform: rotate(45deg);
width: 15px;
height: 15px;
}
.timeline-item:nth-child(odd) .timeline-item-content {
text-align: left;
align-items: flex-start;
}
.timeline-item:nth-child(odd) .timeline-item-content::after {
right: auto;
left: -7.5px;
box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.2);
}
我们正在做几件事:
- 这个包装器有一个固定的
width
和一个max-width
。这是因为我们希望它有一些边界,这意味着如果只有几个单词,我们希望盒子至少足够400px
宽,但如果有很多文本,它不应该占据整个空间(50%
来自.timeline-item
包装器),但文本应该移动到下一行 -> 这就是我们使用第二个包装器的原因:.timeline-item-content
- 和属性用于将内部元素推到左侧或右侧,具体取决于父
text-align
级align-items
- 指向中间线的小箭头
::after
是由选择器上应用的样式决定的。本质上,它是一个box-shadow
应用了旋转的框45deg
- 如上所述,我们通过使用选择器选择父级来设置右侧的样式
:nth-child(odd)
接下来是所有内部元素:
.timeline-item-content .tag {
color: #fff;
font-size: 12px;
font-weight: bold;
top: 5px;
left: 5px;
letter-spacing: 1px;
padding: 5px;
position: absolute;
text-transform: uppercase;
}
.timeline-item:nth-child(odd) .timeline-item-content .tag {
left: auto;
right: 5px;
}
.timeline-item-content time {
color: #777;
font-size: 12px;
font-weight: bold;
}
.timeline-item-content p {
font-size: 16px;
line-height: 24px;
margin: 15px 0;
max-width: 250px;
}
.timeline-item-content a {
font-size: 14px;
font-weight: bold;
}
.timeline-item-content a::after {
content: ' ►';
font-size: 12px;
}
.timeline-item-content .circle {
background-color: #fff;
border: 3px solid #e17b77;
border-radius: 50%;
position: absolute;
top: calc(50% - 10px);
right: -40px;
width: 20px;
height: 20px;
z-index: 100;
}
.timeline-item:nth-child(odd) .timeline-item-content .circle {
right: auto;
left: -40px;
}
这里有几点需要注意:
- 你可能已经猜到了,之所以
.tag
定位,absolute
是因为无论盒子大小如何,我们都希望它保持在左上角(或右上角)。 - 我们想在标签后添加一个小插入符号
a
来突出显示它是一个链接 - 我们创建一个并将其放置在箭头正前方
.circle
的中间线/条的顶部
快完成了!😄 剩下唯一要做的就是添加 CSS,让所有内容都能在所有屏幕尺寸上响应:
@media only screen and (max-width: 1023px) {
.timeline-item-content {
max-width: 100%;
}
}
@media only screen and (max-width: 767px) {
.timeline-item-content,
.timeline-item:nth-child(odd) .timeline-item-content {
padding: 15px 10px;
text-align: center;
align-items: center;
}
.timeline-item-content .tag {
width: calc(100% - 10px);
text-align: center;
}
.timeline-item-content time {
margin-top: 20px;
}
.timeline-item-content a {
text-decoration: underline;
}
.timeline-item-content a::after {
display: none;
}
}
我们有两个媒体查询:
- 在小型笔记本电脑屏幕上,
max-width: 1023px
我们希望能够.timeline-item-content
跨越其父级的整个宽度,因为屏幕较小,否则看起来会很挤 - 在手机上 -
max-width: 767px
- 将设置
.tag
为满width
(为此我们不需要忘记10px
从总数中减去100%
- 这是因为我们将其定位在left: 5px
,所以我们删除该数量的两倍) - 将所有文本居中,并从顶部向下推一点
- 删除链接上的插入符号并添加下划线 - 在移动设备上看起来更好😉
- 将设置
然后...我们完成了!
结论
正如我提到的,这个组件在我的时间线页面上。快来体验一下它的实际效果吧!😄
如果您对本文有任何不明白的地方,请务必联系我,我很乐意回答您的问题!
祝你编程愉快!😇
最初发布于www.florin-pop.com
文章来源:https://dev.to/florinpop17/how-to-create-a-timeline-component-with-react-2dme