四、前端开发—搭建静态网站(3)

之前,我们搭建了网站首页的导航栏 以及 轮播图,接下来,开始搭建博客文章列表组件

搭建文章列表组件

在上一节,我们分析网页架构时,也说过,文章列表和个人资料展示共占一行。大概计算下来 文章列表要占24份中的19份,个人资料占24份中的5份。

首先分别在 my-blog\src\components\show-posts-list\show-posts-list.jsx 和 my-blog\src\components\show-sider\show-sider.jsx 这两处地方新建文件。

show-posts-list.jsx 将会写 文章列表的组件;show-sider.jsx 将会写 个人资料侧边栏的组件。

修改 my-blog\src\components\show\show.jsx 中的部分文件,导入这两个空白组件。

...
import ShowPostsLists from "../../containers/show-posts-lists/show-posts-lists";
import ShowSider from "../../containers/show-sider/show-sider";
...
...
return (
            <>
                <Row style={{"marginBottom": 20}}>
                    <Col span={24}>
                        <Swiper />
                    </Col>
                </Row>
                <Row >
                    <Col  span={19} >
                        <ShowPostsLists />

                    </Col>
                    <Col  span={5}>
                        <ShowSider/>
                    </Col>

                </Row>

            </>
...

接下来,所有的重心就是在 my-blog\src\components\show-posts-list\show-posts-list.jsx 文件中详细编写文章列表组件。

import React, {Component} from "react";
import {Col, Row} from "antd";

export default class ShowPostsList extends Component{
    render() {
        return (
            <Row>
                <Col span={24}> 博客类别导航栏 </Col>
                                {/* 文章列表  */}
                <Col span={6}>
                    <div>
                        <span> 文章标题 </span>
                        <span> 文章摘要 </span>
                        <span> 文章类别 </span>
                        <span> 文章标签 </span>
                    </div>
                </Col>
            </Row>
        )
    }
}

上面的代码页很容易理解,从之前的网页中文章列表结构中我们可以看到,它是由一个 博客类别导航栏 和 一个文章列表 组成的。 同时 博客类别导航栏 独占一行,为了方便起见我是用 Col 组件,将 span 属性设置为 24 ,当然我们也可以继续嵌套 Row 组件。

文章列表中,我们想让它一行显示 4 个文章信息,所以 Col 中的 span 属性是 6 。有人可能会问,文章列表是由好几行组成的,为什么这里只使用一个 Col 就完成了呢? 原因很简单,之前说过,Col 会将 Row 的一行分为了 24 份。但是呢,当 Row 中的 Col 的 span 属性值之和大于 24 时,它就会自动换行。

所以,我们可以尝试多复制几份 <Col span={6}> ... </Col> 这个标签的内容,运行一下,查看效果演示。

拆分出其他组件

我们继续思考,假如我们继续在show-posts-list.jsx 中完善代码以及样式,那么所有的代码就会杂糅到一起,那和不使用 react 还有区别么。所以我们要使用 react 中组件化思想,尽量将能拆分出的组件就拆分出来。我们可以看到,show-posts-list.jsx 可以拆分成两个组件 博客类别导航栏组件,以及文章列表中每一个文章信息的卡片组件

搭建博客类别导航栏组件

在 my-blog\src\components\nav-posts\ 中新建 nav-posts.jsx 文件,写入:

import React, {Component} from "react";

import "./nav-posts.less"

export default class NavPosts extends Component{

    render() {
        return (
            <div className={"categoryNav"}>
                                {/* 不包含子菜单栏 */}
                <div className={`dropdown active`}  style={{marginLeft:0}}>
                    <a><span>最新撰写</span></a>
                </div>
                                {/* 包含子菜单栏 */}
                <div className={`dropdown`}>
                    <span>编程语言</span>
                    <div className={"dropdown-content"}>
                        <p><a>gradle</a></p>
                        <p><a>react</a></p>
                    </div>
                </div>
            </div>
        )
    }
}

上面的 html 代码也很简单,编写了两个分类导航栏,其中一个不包含子菜单栏,另一个可以包含多个子菜单栏。这样就可以根据自己的需求定制特定的网页。

其中引入的类样式 import "./nav-posts.less" 是在同级目录下新建 nav-post.less 文件,并写入:

.categoryNav{
  float:left;
  width: calc(100%);
  position: relative;
  height: 56px;}.dropdown {
  position: relative;
  display: inline-block;
  cursor: pointer;
  line-height: 44px;
  margin-left: 5px;}.categoryNav>.dropdown.active {
  background: #20a0ff;
  border-radius: 10px;
  -webkit-box-shadow: 0 8px 10px rgba(32,160,255,.3);
  box-shadow: 0 8px 10px rgba(32,160,255,.3);}.categoryNav>.dropdown.active > a > span {
  color: #fff;}.categoryNav>.dropdown.active > span {
  color: #fff;}.dropdown span {
  transition: .25s;
  font-size: 14px;
  padding: 0 15px;
  color: #738192;}.dropdown-content {
  left: -32px;
  width: 138px;
  border-radius: 5px;
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  padding: 5px 5px;
  z-index: 999;}.dropdown-content p {
  text-align: center;
  margin-bottom: 0px;}.dropdown-content p.active {
  color: white;
  background: #4fb2fb;
  border-radius: 5px 5px 5px 5px;}.dropdown:hover .dropdown-content {
  display: block;}.dropdown:hover  {
  background: #20a0ff3b;
  border-radius: 10px;
  -webkit-box-shadow: 0 8px 10px rgba(32, 160, 255, .3);
  box-shadow: 0 8px 10px rgba(32, 160, 255, .3);}.dropdown-content p{
  text-align: center;
  margin-bottom: 0px;}.dropdown-content p:hover{
  color: white;
  background: #20a0ff3b;
  border-radius: 5px 5px 5px 5px;}.dropdown-content p:hover a{
  color: white;}.dropdown-content a{
  text-decoration: none;
  color: #738192;}

最后将我们写好的静态的博客文章类别导航栏组件导入到 show-posts-list.jsx 中,即 修改 my-blog\src\components\show-posts-list\show-posts-list.jsx 中部分代码:

...
import NavPosts from "../nav-posts/nav-posts";  // 导入组件
...
...
                        <Row>
                <Col span={24}> <NavPosts /> </Col>   {/*引入组件*/}
                <Col span={6}>
                    <div>
                        <span> 文章标题 </span>
                        <span> 文章摘要 </span>
                        <span> 文章类别 </span>
                        <span> 文章标签 </span>
                    </div>
                </Col>
            </Row>
...

启动运行博客项目,就可看到相应的界面效果了。

数据与 html 样式相分离

在 my-blog\src\components\nav-posts\nav-posts.jsx 文件中,不难发现,导航栏分类的数据都和 html 代码杂糅到一起。

当我们想要修改数据时,那就需要一处一处的代码去修改,像我们这么懒的人,这可能么?当然不可能去做。

所以,需要将数据与 html 代码相分离。之后,我们只需要添加、删除数据,html 就会最相应的渲染。省时省力,完美!!!

修改my-blog\src\components\nav-posts\nav-posts.jsx 文件中的代码如下:

import React, {Component} from "react";

import "./nav-posts.less"

export default class NavPosts extends Component{

    state = {
        current: 3,
        sub_current: -1,
        categories_data:[
            {
                id: 3,
                name:"最新撰写"
            },
            {
                id: 7,
                name:"编程语言",
                cub_cate:[
                    {
                        name:"gradle",
                        id: 3,
                    },
                    {
                        name:"React",
                        id: 7,
                    }
                ]

            }
        ]
    }

    handleClick = (id, sub_id) => {
        console.log(id)
        this.setState({ current: id,sub_current: sub_id });
    };

    render() {

        const {categories_data,current,sub_current} = this.state

        return (
            <div className={"categoryNav"}>
                {
                    categories_data.map((category,index) => (
                        <div className={`dropdown ${current === category.id ? 'active' : null }`}
                             onClick={category.cub_cate === undefined && current !== category.id ? this.handleClick.bind(this,category.id) : null }
                             style={{marginLeft:0}} key={index} >
                            <span>{category.name}</span>
                            { category.cub_cate === undefined ? null : (
                                <div className={"dropdown-content"}>
                                    { category.cub_cate.map((cate, index) => (
                                        <p className={sub_current === cate.id ? 'active' : null }
                                           onClick={sub_current !== cate.id ? this.handleClick.bind(this, category.id, cate.id):null}
                                           key={index} >{cate.name}</p>
                                    ) ) }
                                </div>
                            ) }
                        </div>
                    ))
                }
            </div>
        )
    }
}

看着可能有些复杂,但是仔细研究一下的话,是非常简单的,如果又不懂的话,我将在下一段简单的介绍一下其中用到的语法,如果已经了解了的话,请跳过下面一段话,进入下一阶段吧!

首先 state 我们之前也用到过,它称为组件状态,它保管着我们组件的数据以及状态。其中,我设计了三个状态,current 、sub_currentcategories_data

current 代表着已经被选中的菜单的 id;当菜单中存在 子菜单栏时,sub_current 代表着已经被选中的子菜单的 id;categories_data 代表着存放的数据,未来动态数据就将存放于此。current 和 sub_current 的作用就是判断菜单是否被选中,同时选中菜单的样式将会发生变化。

const {categories_data,current,sub_current} = this.state 这行代码之前也用到过,它是将上方 state 中的三个对象引入进来,方便下方代码使用。

在 html 代码中有两个语法在频繁的使用,未来它们使用的次数也非常的高,就是一下俩种,是很常用的 js 语法:

{ 数组对象.map((aaa,index) => ( 此处写循环代码 ) ) } 这个已经写的很清楚了,这是一个循环数组的方法,其中 aaa 为每个循环时数组对象中的每个一对象,index 为 循环次数,它们两个使用范围仅在 循环体中使用

{ 判断条件 ? 条件为真时执行的代码 : 条件为假时执行的代码 } 这个已经也写的很清楚了,就是一个简单的判断语句。

OnClick 属性,顾名思义,指的就是当用户点击时执行的函数。

效果图

编写卡片组件

在之前分析时,我们就聊到,文章列表在当前网页是以一张纸卡片排列而成,所以我们需要一个卡片组件来展示文章信息。尽管antd 中有现成的卡片组件,但是它不符合我们的需求,所以需要专门定制化一个卡片组件。

首先,新建卡片组件文件,即在 my-blg\src\components\card\ 中创建 card.jsx 文件,并写入:

import React, {Component} from "react";

import "./card.less"

export default class Card extends Component{
    render() {
        return (
            <div className={"card"}>
                <a>
                    <div className={"card-image"}>
                        <img src={"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4166449390,244951508&fm=26&gp=0.jpg"} />
                        <span className={"card-title"}>标题</span>
                        <span className={"posts-date"}>
                            2020年1月30日
                        </span>
                    </div>
                </a>
                <div className={"card-content  article-content"}>
                    <div className={"summary"}>
                        文章摘要。。。。
                    </div>
                </div>
                <div className={"card-action article-tags"}>
                    <a><span className={"chip tag-color"}>标签-1</span> </a>
                    <a><span className={"chip tag-color"}>标签-2</span> </a>
                </div>
            </div>
        )
    }
}

上面的代码也很简单,对样式的制作,主要是通过百度搜索,以及其他相关网站代码的"借鉴",(假如大家都不知道如何借鉴的话,以后有机会分享一下)。

同样,为了达到相应的效果,我们在同级目录新建样式文件 card.less ,写入样式:

.card{
  border-radius: 8px;
  overflow: hidden;
  background-color: #fff;
  padding-bottom: 5px;
  transition: all 250ms cubic-bezier(.02, .01, .47, 1);}.card a {
  margin-right: 0 !important;
  color: #525f7f;
  text-transform: none !important;}.card .card-content {
  padding: 15px 15px 12px 18px;
  border-radius: 0 0 2px 2px;}.card .card-action:last-child {
  border-radius: 0 0 2px 2px;}.card .card-image {
  transition: 1s;
  position: relative;
  background: #000;}.card .card-image img {
  opacity: 0.5;
  transition: 1s;}.card:hover {
  box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
  transform: translate(0,-5px);
  transition-delay: 0s !important;
  border-color: transparent;}.card:hover img {
  opacity: 1;}.card:hover .card-image {
  background: #fff;}.card .card-image img {
  width: 100%;
  border-radius: 8px 8px 0 0;}.card .card-image .card-title {
  color: #fff;
  position: absolute;
  bottom: 0;
  left: 0;
  max-width: 100%;
  padding: 24px;}.card .card-image .posts-date {
  color: #cacaca;
  font-size: 12px;
  position: absolute;
  bottom: 30px;
  left: 0px;
  max-width: 100%;
  padding: 24px;}.card .card-title {
  font-size: 24px;
  font-weight: 300;}.card .article-content .summary {
  padding-bottom: 2px;
  padding-left: 0;
  margin-bottom: 6px;
  word-break: break-all;}.summary {
  overflow: hidden;
  position: relative;
  line-height: 1.5em;
  max-height: 4.5em;
  text-align: justify;
  margin-right: -1em;
  padding-right: 1em;}.summary:before {
  content: '...';
  position: absolute;
  right: 15px;
  bottom: 0;}.summary:after {
  content: '';
  position: absolute;
  right: 15px;
  width: 1em;
  height: 1.5em;
  margin-top: 0.2em;
  background: white;}.article-content .post-category {
  float: right;
  padding-left: 5px;}.tag-color {
  background-image: linear-gradient(to left, #00c9ff 0%, #66a6ff 100%);}.chip {
  display: inline-block;
  height: 32px;
  font-size: 13px;
  font-weight: 500;
  color: rgba(0,0,0,0.6);
  line-height: 32px;
  padding: 0 12px;
  border-radius: 16px;
  background-color: #e4e4e4;
  margin-bottom: 5px;
  margin-right: 5px;}.card .article-tags .chip {
  margin: 2px;
  font-size: 0.8rem;
  font-weight: 400;
  height: 22px;
  line-height: 22px;
  color: #fff;
  border-radius: 10px;}.article-tags{
  padding-left: 14px;}

其中,文章列表有一个小优化,即在鼠标未悬浮时,图片会有一个黑色的蒙版。当鼠标悬浮时,就会消失。这个为图片添加蒙版的效果有一个参考,地址如下: https://blog.csdn.net/yunsiwl5/article/details/80365956

数据与 html 样式相分离

原因如之前所言,都是为了给之后的动态数据提供基础,card.jsx 的代码修改如下:

import React, {Component} from "react";

import "./card.less"

export default class Card extends Component{

    state = {
        img_src:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4166449390,244951508&fm=26&gp=0.jpg",
        title:"",
        abstract:"文章摘要。。。。",
        create_time:"2020年1月30日",
        category:"gradle",
        tags:[{
            id:0,
            name:"标签-1",
        },{
            id:2,
            name:"标签 - 2",
        },],
    }

    render() {
        const {img_src,tags,title,abstract,category,create_time} = this.state
        return (
            <div className={"card"}>
                <a>
                    <div className={"card-image"}>
                        <img src={img_src} />
                        <span className={"card-title"}>{title}</span>
                        <span className={"posts-date"}>
                            {create_time}&nbsp;&nbsp;·&nbsp;&nbsp;{category}
                        </span>
                    </div>
                </a>
                <div className={"card-content  article-content"}>
                    <div className={"summary"}>
                        {abstract}
                    </div>
                </div>
                <div className={"card-action article-tags"}>
                    {tags.map((tag,index) => (
                        <a key={index}> <span className={"chip tag-color"}> {tag.name} </span> </a>
                    ))}
                </div>
            </div>
        )
    }
}

最后同样将我们写好的静态的卡片组件导入到 show-posts-list.jsx 中,即 修改 my-blog\src\components\show-posts-list\show-posts-list.jsx 中部分代码:

下面代码中,我们只插入了3张文章卡片,这个是可以根据需求添加无数个卡片的。

import React, {Component} from "react";
import {Col, Row} from "antd";

import NavPosts from "../nav-posts/nav-posts";
import Card from "../card/card";   // 导入卡片组件

export default class ShowPostsList extends Component{
    render() {
        return (
            <Row gutter={[32, 24]}>
                <Col span={24}> <NavPosts /> </Col>
                                {/* 导入三张文章卡片 */}
                <Col span={6}>
                    <Card />
                </Col>
                <Col span={6}>
                    <Card />
                </Col>
                <Col span={6}>
                    <Card />
                </Col>
            </Row>
        )
    }
}

这样,静态网站的第二小模块就算搭建完成了,赶紧运行查看一下吧! 哦哦,对了,细心的小伙伴会发现 Row 中出现了 gutter={[32, 24]} 这个属性,我们可以尝试删除它,运行一遍,看有什么差异,或者查询 antd 文档,看一下它们有什么作用吧!

最后的效果图:

再然后微调一下间距,展示一下最后的效果图吧:

END

 

 

 

这个公众号分享一些

我平时的胡思乱想和其他东西

如果您稍微感兴趣

可以关注一下

 

 

                                 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐