在本教程中,我将指导您完成创建图像轮播组件的过程,该组件看起来就像您在许多 OTT 平台(想想 Netflix)上看到的一样。
我们将从创建原子组件开始,例如Tags
、Description
、Title
等,它们将显示有关每个电影标题的各种信息。然后,我们将通过复合模式将这些组件拼接在一起,以创建一个Banner
以图像形式显示每个电影标题的组件。最后,我们将使用该HeroBanner
组件使用包构建图像轮播组件Swiper
。
(更多优质教程:java567.com,搜"ts")
到本文结束时,您将掌握创建美观且实用的图像轮播组件的知识和技能,这将给您的用户留下深刻印象。让我们开始吧!
目录
-
先决条件
-
如何构建横幅组件
-
如何构建单个组件
-
如何使用复合图案将所有组件缝合在一起
-
如何构建图像轮播组件
-
概括
先决条件
在继续下一节之前,请确保您熟悉以下主题:
-
CSS – 需要 CSS 的中级知识来设置我们将在本文中创建的小组件的样式。
-
Styled components——你需要熟悉 styled-components 是什么,因为我们将使用它来创建一个包含静态/动态 css 的组件版本。
-
复合 模式——我们将使用此模式将各个组件拼接在一起,以便以后可以方便地使用它们。
-
TypeScript – 我们将在整个教程中使用TypeScript 。它在 JavaScript 之上提供了良好的类型安全。对它有一些基本的了解肯定会在这里有所收获。
如何构建横幅组件
下面的 gif 表示图像轮播组件。如果您不知道什么是图像轮播,那么让我给您做一个简要的概述。
图像轮播是一个组件,由旋转固定次数或可以在导航图标的帮助下旋转的图像组成。
在本教程中,我们将创建此组件。但在进入图像轮播之前,我们将从一个非常基本的组件开始,即横幅组件。
Banner Component 将成为一个帮助我们显示的组件:
-
标题
-
标签
-
描述
-
背景图
之后,在styled-components和 CSS的帮助下,我们会让它看起来像我们在大多数 OTT 平台上看到的一样漂亮。
构建此组件涉及以下步骤:
-
构建各个组件
-
将所有组件与复合图案拼接在一起
如何构建单个组件
我们的横幅组件将由一些无法进一步分解的基本较小组件组成。这些组件称为原子组件。让我们首先构建最简单的组件,即 Title 组件:
首先,创建一个如下所示的功能组件:
const Title = (props: { title: string }) => <div>{props.title}</div>;
我们还需要设置此组件的样式。我们创建一个带样式的 div 组件并将其放置在上面的 Title 组件中,如下所示:
const StyledTitle = styled.div`
font-size: 28px;
font-weight: 600;
color: white;
`;
const Title = (props: { title: string }) => (
<StyledTitle>{props.title}</StyledTitle>
);
我们阵容中的下一个组件是Tags
组件。它是一个 div 元素,它映射到字符串(标签)并将它们显示在元素中span
:
创建一个函数式组件,它接受一个字符串数组作为 prop,并使用 map 函数将它们显示在 span 元素中:
const Tags = (props: { tags: string[] }) => {
return (
<div>
{props.tags.map((tag: string, index: number) => (
<span key={`tag-${tag}-index`}>{tag}</span>
))}
</div>
);
};
现在让我们创建一个样式化的 div 组件,作为上述 div 元素的替代品。我们创建这个包装器组件来将样式应用于子元素:
const StyledTag = styled.div`
padding: 0.5rem 0;
& span {
margin-right: 0.5rem;
font-size: 1rem;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
}
`;
最后,我们将这些组件拼接在一起:
const Tags = (props: { tags: string[] }) => {
return (
<StyledTag>
{tags.map((tag: string, index: number) => (
<span key={`tag-${tag}-index`}>{tag}</span>
))}
</StyledTag>
);
};
同样,我们创建另一个组件,称为Description
组件。它有助于显示电影标题的描述。它也是一个功能组件,它接受描述道具并使用样式化组件显示它:
const StyledDescription = styled.div`
text-align: start;
color: rgba(255, 255, 255, 0.8);
display: -webkit-box;
max-width: 50%;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
`;
const Description = (props: { description: string }) => (
<StyledDescription>{description}</StyledDescription>
);
最后,我们将创建Banner
组件。该组件的目的是显示电影标题的背景图像以及传递给它的子项。让我们创建这个组件的一个非常基本的版本:
const Banner = (props) => {
return (
<div
style={{
backgroundImage: `url(${props.image})`,
width: "100%",
height: "400px",
}}
>
<div>{props.children}</div>
</div>
);
};
<Banner image="https://m.media-amazon.com/images/M/MV5BZjRlNDUxZjAtOGQ4OC00OTNlLTgxNmQtYTBmMDgwZmNmNjkxXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_.jpg">
<h1 style={{ color: "yellow" }}>Die hard</h1>
</Banner>;
如果我们执行这个组件,它会做我们期望的事情,“显示背景图像和子组件”,如下所示:
但是风格似乎不对——我们不希望这个组件看起来这么难看。我们需要的是应用 CSS 将事物放在正确的位置 ?(双关语)。
我们希望电影海报在右边,所有子组件都应该在它的左边。现在让我们创建一个样式化的组件来做到这一点:
const StyledContainer = styled.div`
height: 400px;
width: 100%;
display: flex;
background-image: linear-gradient(90deg, rgba(0, 0, 0, 1) 60%, transparent),
url(${(props) => props.image});
background-size: contain;
background-repeat: no-repeat;
background-position: right;
& > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding-left: 10px;
}
`;
const Banner = (props) => {
return (
<StyledContainer image={props.image}>
<div>{props.children}</div>
</StyledContainer>
);
};
<Banner image="https://m.media-amazon.com/images/M/MV5BZjRlNDUxZjAtOGQ4OC00OTNlLTgxNmQtYTBmMDgwZmNmNjkxXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_.jpg">
<h1 style={{ color: "yellow" }}>Die hard</h1>
</Banner>;
我们创建了一个名为 的新样式组件StyledContainer
。它由 CSS 组成,它将图像右对齐并在容器周围应用黑色渐变,以便只有电影标题可见。
接下来,在该& > div
部分中,我们确保所有子组件都左对齐。这是它的样子:
耶皮耶!我们的 Banner 组件已准备就绪。现在让我们用上面创建的所有组件测试这个横幅组件。将Title
, Tags
, 和Description
组件放在Banner
组件内部,如下所示:
<Banner image="https://m.media-amazon.com/images/M/MV5BZjRlNDUxZjAtOGQ4OC00OTNlLTgxNmQtYTBmMDgwZmNmNjkxXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_.jpg">
<Title title="Die Hard" />
<Tags tags={["Action", "Thriller"]} />
<Description description="NYPD cop John McClane's plan to reconcile with his estranged wife is thrown for a serious loop when, minutes after he arrives at her office, the entire building is overtaken by a group of terrorists. With little help from the LAPD, wisecracking McClane sets out to single-handedly rescue the hostages and bring the bad guys down." />
</Banner>;
这就是我们的 Banner 组件的样子。
如何使用复合图案将所有组件缝合在一起
我们希望我们的 Banner 组件易于使用,并且应该灵活。我们可以借助复合模式将 Title、Tags 和 Description 组件拼接到 Banner 组件中。
使用此模式创建的组件在其内部组件之间共享状态和逻辑。这种复合模式的一个例子是语义 UI 提供的菜单组件。
<Menu>
<Menu.Item />
</Menu>;
使用这种模式的好处是我们只需要导入一个组件——在我们的例子中我们只导入 Banner 组件。它的所有内部组件都可以直接使用,如下所示:
<Banner.Title />
<Banner.Tags />
<Banner.Description />
现在让我们开始为我们的 Banner 组件做同样的事情。
由于我们已准备好所有组件,因此我将它们放在一个文件中:
import "./styles.css";
import styled from "styled-components";
import React from "react";
export type BannerProps = {
title: string,
tags: string[],
description: string,
image: string,
};
const StyledTitle = styled.div`
font-size: 28px;
font-weight: 600;
color: white;
`;
const StyledTag = styled.div`
padding: 0.5rem 0;
& span {
margin-right: 0.5rem;
font-size: 1rem;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
}
`;
const StyledDescription = styled.div`
text-align: start;
color: rgba(255, 255, 255, 0.8);
display: -webkit-box;
max-width: 50%;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
`;
const Container = styled.div`
height: 400px;
width: 100%;
display: flex;
background-image: linear-gradient(90deg, rgba(0, 0, 0, 1) 60%, transparent),
url(${(props: Pick<BannerProps, "image">) => props.image});
background-size: contain;
background-repeat: no-repeat;
background-position: right;
& > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding-left: 10px;
}
`;
const Title = ({ title }: Pick<BannerProps, "title">) => (
<StyledTitle>{title}</StyledTitle>
);
const Tags = ({ tags }: Pick<BannerProps, "tags">) => {
return (
<StyledTag>
{tags.map((tag) => (
<span key={`tag-${tag}`}>{tag}</span>
))}
</StyledTag>
);
};
const Description = ({ description }: Pick<BannerProps, "description">) => (
<StyledDescription>{description}</StyledDescription>
);
const Banner = (props: any) => {