Skip to content

静态结构创建

筛选区结构搭建

image.png

  1. 如何让 RangePicker 日期范围选择框选择中文
  2. Select 组件配合 Form.Item 使用时,如何配置默认选中项

代码实现

pages/Article/index.jsx

jsx
import {
  Breadcrumb,
  Button,
  Form,
  Input,
  Select,
  message,
  Radio,
  Divider,
  DatePicker,
} from "antd";
import {
  HomeOutlined,
  ContainerOutlined,
  SearchOutlined,
} from "@ant-design/icons";
import { useEffect, useState } from "react";
import locale from "antd/es/date-picker/locale/zh_CN";
const Article = () => {
  const { RangePicker } = DatePicker;
  // 频道列表
  const [channels, setChannels] = useState([]);
  return (
    <div className="Article">
      {/* 面包屑导航 */}
      <Breadcrumb
        items={[
          {
            title: (
              <>
                <HomeOutlined />
                <span>首页</span>
              </>
            ),
          },
          {
            title: (
              <>
                <ContainerOutlined />
                <span>文章列表</span>
              </>
            ),
          },
        ]}
      />
      <Divider />
      {/* 搜索项 */}
      <Form initialValues={{ status: "" }} autoComplete="off" layout="inline">
        <Form.Item label="状态" name="status">
          <Radio.Group>
            <Radio value={""}> 全部 </Radio>
            <Radio value={0}> 草稿 </Radio>
            <Radio value={2}> 审核通过 </Radio>
          </Radio.Group>
        </Form.Item>
        <Form.Item label="频道" name="channel_id">
          <Select showSearch placeholder="请选择频道" optionFilterProp="label">
            {channels.map((item) => (
              <Select.Option key={item.id} value={item.id}>
                {item.name}
              </Select.Option>
            ))}
          </Select>
        </Form.Item>
        <Form.Item label="日期" name="date">
          {/* 传入locale属性 控制中文显示*/}
          <RangePicker locale={locale}></RangePicker>
        </Form.Item>
        <Form.Item>
          <Button type="primary" icon={<SearchOutlined />} htmlType="submit">
            查询
          </Button>
        </Form.Item>
      </Form>
    </div>
  );
};
export default Article;

表格区域结构

image.png代码实现

jsx
// 导入资源
import { Table, Tag, Space } from "antd";
import { EditOutlined, DeleteOutlined } from "@ant-design/icons";
import img404 from "@/assets/error.png";

const Article = () => {
  // 准备列数据
  const columns = [
    {
      title: "封面",
      dataIndex: "cover",
      width: 120,
      render: (cover) => {
        return (
          <img src={cover.images[0] || img404} width={80} height={60} alt="" />
        );
      },
    },
    {
      title: "标题",
      dataIndex: "title",
      width: 220,
    },
    {
      title: "状态",
      dataIndex: "status",
      render: (data) => <Tag color="green">审核通过</Tag>,
    },
    {
      title: "发布时间",
      dataIndex: "pubdate",
    },
    {
      title: "阅读数",
      dataIndex: "read_count",
    },
    {
      title: "评论数",
      dataIndex: "comment_count",
    },
    {
      title: "点赞数",
      dataIndex: "like_count",
    },
    {
      title: "操作",
      render: (data) => {
        return (
          <Space size="middle">
            <Button type="primary" shape="circle" icon={<EditOutlined />} />
            <Button
              type="primary"
              danger
              shape="circle"
              icon={<DeleteOutlined />}
            />
          </Space>
        );
      },
    },
  ];
  // 准备表格body数据
  const data = [
    {
      id: "8218",
      comment_count: 0,
      cover: {
        images: [],
      },
      like_count: 0,
      pubdate: "2019-03-11 09:00:00",
      read_count: 2,
      status: 2,
      title: "wkwebview离线化加载h5资源解决方案",
    },
  ];
  return (
    <div>
      ...
      <Table rowKey="id" columns={columns} dataSource={data} />
    </div>
  );
};

获取频道数据

自定义 Hooks 是一个函数,其名称以 use 开头,函数内部可以调用 React 的 Hooks,也可以返回一些数据给调用者。

实现步骤

  1. 创建 useChannel.js 文件,封装获取频道列表的逻辑
  2. 在列表页中引入 useChannel.js 文件
  3. 解构hooks,获取频道列表数据

代码实现

jsx
// 封装获取频道列表的逻辑
import { useState, useEffect } from "react";
import http from "@/utils/http";
export default function useChannel() {
  const [channelList, setChannelList] = useState([]);

  useEffect(() => {
    function getChannelList() {
      http.get("/channels").then((res) => {
        setChannelList(res.data.channels);
      });
    }
    getChannelList();
  }, []);

  return { channelList, setChannelList };
}
jsx
import useChannel from "@/hooks/useChannel";

const Article = () => {
  const { channelList } = useChannel();
  return (
    ...
    <Form.Item label="频道" name="channel_id">
      <Select
        showSearch
        placeholder="请选择频道"
        optionFilterProp="label"
        style={{ width: 180 }}
      >
        {channelList.map((item) => (
          <Select.Option key={item.id} value={item.id}>
            {item.name}
          </Select.Option>
        ))}
      </Select>
    </Form.Item>
  );
};

渲染表格数据

image.png

实现步骤

  1. 声明列表相关数据管理
  2. 使用 useState 声明参数相关数据管理
  3. 调用接口获取数据
  4. 使用接口数据渲染模板

代码实现

jsx
const Article = () => {
  // 省略部分代码...
  // 文章列表数据管理
  const [article, setArticleList] = useState({
    list: [],
    count: 0,
  });

  const [params, setParams] = useState({
    page: 1,
    per_page: 4,
    begin_pubdate: null,
    end_pubdate: null,
    status: null,
    channel_id: null,
  });

  // 获取文章列表
  const fetchArticleList = () => {
    http.get("/mp/articles", { params }).then((res) => {
      const { results, total_count } = res.data;
      console.log('results', res.data);

      setArticleList({
        list: results,
        count: total_count
      })
    })
  }

  useEffect(() => {
    fetchArticleList()
  }, [params])

  // 模板渲染
  return (
    ...
    {/* 表格 */}
    <Table rowKey="id" columns={columns} dataSource={articleList.list} scroll={{ y: 550 }} />
  );
};

笔记

useEffect会根据依赖性params的变化触发,当依赖项发生变化时,useEffect中的函数会重新执行。

渲染审批状态

实现步骤

  1. 定义审核状态枚举
  2. 渲染状态数据
jsx
import { Tag } from "antd";
const Article = () => {
  // 定义审核状态枚举
  const statusMap = {
    0: <Tag color="info">草稿</Tag>,
    1: <Tag color="primary">待审核</Tag>,
    2: <Tag color="success">审核通过</Tag>,
    3: <Tag color="warning">审核失败</Tag>,
  }
  // 准备列数据
  const columns = [
    ...
    {
      title: '状态',
      dataIndex: 'status',
      render: data => statusMap[data]
    }
  ]
  return ( 

  )
}

筛选功能实现

实现步骤

  1. 使用useState管理查询参数
  2. 当参数变化时,useEffect会触发fetchArticleList函数查询列表
  3. 提供了onSearch函数来处理搜索条件的更新

代码实现

jsx
import { useEffect, useState } from "react";
import http from "@/utils/http";

const Article = () => {
  const [params, setParams] = useState({page: 1, per_page: 6, begin_pubdate: null, end_pubdate: null, status: null, channel_id: null,})

  // 搜索
  const onSearch = values => {
    console.log(values);
    const { status, channel_id, date } = values
    setParams(
      {
        ...params,
        status, channel_id,
        begin_pubdate: date && date[0].format("YYYY-MM-DD"),
        end_pubdate: date && date[1].format("YYYY-MM-DD"),
      }
    )
  };
    // 获取文章列表
  const fetchArticleList = () => {
    http.get("/mp/articles", { params }).then((res) => {
      const { results, total_count } = res.data;
      console.log('results', res.data);

      setArticleList({
        list: results,
        count: total_count
      })
    })
  }

  useEffect(() => {
    fetchArticleList()
  }, [params])
}

分页功能实现

实现步骤

  1. 为 Table 组件指定 pagination 属性来展示分页效果
  2. 在分页切换事件中获取到筛选表单中选中的数据
  3. 修改 params 参数依赖引起接口重新调用获取最新数据
  4. 通过showTotal 属性来指定分页的显示格式

代码实现

jsx
const pageChange = (page) => {
  // 拿到当前页参数 修改params引起接口更新
  setParams({
    ...params,
    page,
  });
};

return (
  <Table
    rowKey="id"
    columns={columns}
    dataSource={article.list}
    pagination={{
      current: params.page,
      pageSize: params.per_page,
      onChange: pageChange,
      total: article.count,
      showTotal: (total) => `共 ${total} 条数据`,
    }}
  />
);

删除功能

image.png实现步骤

  1. 创建delArticle函数,删除文章
  2. 删除成功后,重新获取文章列表数据

代码实现

jsx
// 删除回调
const delArticle = async (data) => {
    await http.delete(`/mp/articles/${data.id}`)
    // 更新列表
    setParams({
      page: 1,
      per_page: 10
    })
}

const columns = [
  // ...
  {
      title: '操作',
      render: data => {
        return (
          <Space size="middle">
            <Button type="primary" shape="circle" icon={<EditOutlined />} />
            <Popconfirm
              title="确认删除该条文章吗?"
              onConfirm={() => delArticle(data)}
              okText="确认"
              cancelText="取消"
            >
              <Button
                type="primary"
                danger
                shape="circle"
                icon={<DeleteOutlined />}
              />
            </Popconfirm>
          </Space>
        )
  }
]

编辑文章跳转

实现步骤

  1. 给编辑按钮绑定点击事件
  2. 使用navagite跳转到编辑页面

代码实现

jsx
const navigate = useNavigate()
const columns = [
  // ...
  {
    title: "操作",
    render: (data) => (
      <Space size="middle">
        <Button
          type="primary"
          shape="circle"
          icon={<EditOutlined />}
          onClick={() => navagite(`/publish?id=${data.id}`)}
        />
        />
      </Space>
    ),
  },
];