React markdown发布文章后展示[1]

256 阅读2分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

源码地址: https://gitee.com/yang-yiming1234/umi_blog

前言

我们之前的文章已经实现了用markdown创建文章并且存入数据库中。如果想看之前的发布markdown的几篇文章,请看我的专栏 模仿掘金做个博客

那么这篇文章我们对存入数据库中的文章进行一个展示。我们这篇文章先实现一下如下的一个首页。

image.png 先说一下布局,我们就按照布局讲解:

  1. 头部 包括以下内容
  • tabs
  • 搜索框
  • 用户头像
  1. 主要内容
  • 左侧固定导航
  • 中部的文章简介
  • 右边的一个日历和一个天气展示

布局样式

<div className={style.container}>
      <div className={style.top}>
        <div className={style.top_left}>
           Tabs
        </div>
        <div className={style.top_center}>
           搜索框
        </div>
        <div className={style.top_right}>
          <div className={style.avator_con}>
             头像
          </div>
          <div className={style.author}>
            用户姓名标签
          </div>
        </div>
      </div>
      <div className={style.middle}>
        <div className={style.nav}>
         左侧导航
        </div>
        <div className={style.content}>
           文章简介展示
        </div>
        <div className={style.mine}>
          <Calender />
          <div className={style.mine_bottom}>
            <Weather />
          </div>
        </div>
      </div>
    </div>

头部

这里最好下载一下源码,然后对照着看。 image.png

Tabs搜索

image.png

Tabs组件

    // 引入 Tabs组件
    import { Tabs } from 'antd';
    // 解构出 TabPane    
    const { TabPane } = Tabs;
    // 文章类型 Tabs用的数据
    const [articleType, setArticleType] = useState([]);
    // 查询文章接口 tabs和搜索框共用
    const searchAuthorOrTitle = (search=searchParams) => {
    getArticle(search).then(res => {
      const { data } = res;
      setArticles(data);
    });
  };
    // 在useEffect中请求接口 也就是页面加载就请求
    useEffect(() => {
     // 请求文章类型接口
    getArticleType({}).then(res => {
      // 这个数据作为Tabs的“全部”选项 传空参数
      let temp = [{ id: 0, type: '' }];
      // 将{ id: 0, type: '' }和接口数据合并 
      temp = [...temp, ...res.data];
      // 赋值给articleType
      setArticleType(temp);
    });
  }, []);
     <div className={style.top_left}>
          <Tabs
            // 正常来说 key最好别用中文我这里为了方便key都是中文。
            // defaultActiveKey 默认选中的key
            defaultActiveKey={'全部'}
            // 选择其他Tab
            onChange={key => {
             //改变查询参数
              setSearchParams({ ...searchParams, type: key });
             // 调用查询文章接口
              searchAuthorOrTitle({ ...searchParams, type: key });
            }}
          >
          {/*  渲染Tabs */}
            {articleType.map((item, index) => (
            // 如果type的值是空 展示 '全部'
              <TabPane tab={item.type === '' ? '全部' : item.type} key={item.type} />
            ))}
          </Tabs>

对应样式

.top {
    width: 100%;
    height: 70px;
    text-align: center;
    padding: 10px;
    display: flex;
    // 固定
    position: fixed;
    z-index: 9;
    background-color: #eff0f4;

    .top_left {
      flex: 1;
      padding-left: 20px;
      padding-right: 20px;
    }
}

输入框搜索

Input组件

  • 这里将按钮放入了输入框内部,用的是suffix这个属性。然后按钮里用到了图标SearchOutlined
  • 我们这个输入框想要查询题目和作者,那么我们就同时将查询参数的title和username都赋值 在后端的SQL语句中使用OR条件进行查询。
import { Col, Row, Input, Button, Tabs, Tag, Avatar } from 'antd';
import { SearchOutlined, GithubOutlined, CalendarOutlined } from '@ant-design/icons';

      <div className={style.top_center}>
          <Input
            placeholder="搜索🔍题目、作者"
            style={{ borderRadius: '20px', width: '100%' }}
            // 改查询参数
            onChange={e => {
              setSearchParams({
                title: e.target.value,
                username: e.target.value,
              });
            }}
            suffix={(
            // 点击按钮调用查询接口也就是跟刚才Tabs一样的接口              
            <Button
                type="primary"
                shape="circle"
                icon={<SearchOutlined />}
                onClick={() => {
                  searchAuthorOrTitle();
                }}
              />
            )}
          />
        </div>

样式

只是控制 搜索框的位置 和长度

 .top_center {
      flex: 1;
    }

头像

Avatar组件

  • 如果不使用Avatar组件,我们用img去渲染头像的话。会失真、形状改变。

  • Tag 组件 传入 color参数来改变颜色

import { Col, Row, Input, Button, Tabs, Tag, Avatar } from 'antd';
    <div className={style.top_right}>
          <div className={style.avator_con}>
            <Avatar
              className={style.avator}
              src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
            />
          </div>
          <div className={style.author}>
            <Tag color="#108ee9">{userInfo.username}</Tag>
          </div>
        </div>

样式

  .top_right {
      flex: 1;
      padding-right: 10px;
      display: flex;
      justify-content: right;

      .avator_con {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        margin-right: 5px;

        .avator {
          width: 50px;
          height: 50px;
          border-radius: 50%;
       
        }
      }

      .author {
        line-height: 50px;
        font-weight: 600;
      }

    }