极客园PC-第4章 文章列表

文章列表功能

card组件与面包屑导航

import { Card } from 'antd'
export default class ArticleList extends Component {
  render() {
    return (
      <div className="articleList">
        <Card title="面包屑导航">我是内容</Card>
      </div>
    )
  }
}
  • 面包屑导航的使用
export default class ArticleList extends Component {
  render() {
    return (
      <div className={styles.root}>
        <Card
          title={
            <Breadcrumb>
              <Breadcrumb.Item>
                <Link to="/home">首页</Link>
              </Breadcrumb.Item>
              <Breadcrumb.Item>文章列表</Breadcrumb.Item>
            </Breadcrumb>
          }
        >
          内容
        </Card>
      </div>
    )
  }
}

搜索表单基本结构

  • 复制表单的基本结构到组件中
  • 修改表单结构
<Card
  title={
    <Breadcrumb separator="/">
      <Breadcrumb.Item>
        <Link to="/home">首页</Link>
      </Breadcrumb.Item>
      <Breadcrumb.Item>文章列表</Breadcrumb.Item>
    </Breadcrumb>
  }
>
  <Form>
    <Form.Item label="状态" name="username">
      <Input />
    </Form.Item>

    <Form.Item label="频道" name="password">
      <Input.Password />
    </Form.Item>

    <Form.Item label="日期" name="password">
      <Input.Password />
    </Form.Item>

    <Form.Item>
      <Button type="primary" htmlType="submit">
        筛选
      </Button>
    </Form.Item>
  </Form>
</Card>
  • 状态的基本结构
<Form initialValues={{ status: null }}>
  <Form.Item label="状态" name="status">
    <Radio.Group>
      <Radio value={null}>全部</Radio>
      <Radio value={0}>草稿</Radio>
      <Radio value={1}>待审核</Radio>
      <Radio value={2}>审核通过</Radio>
      <Radio value={3}>审核失败</Radio>
    </Radio.Group>
  </Form.Item>
  • 下拉框结构
<Form.Item label="频道" name="password">
  <Select placeholder="请选择频道" style={{ width: 200 }}>
    <Option value="jack">Jack</Option>
    <Option value="lucy">Lucy</Option>
    <Option value="Yiminghe">yiminghe</Option>
  </Select>
</Form.Item>
  • 日期选择基本结构
import { Card, Breadcrumb, Form, Button, Radio, Select, DatePicker } from 'antd'
const { RangePicker } = DatePicker

<Form.Item label="日期" name="password">
  <RangePicker />
</Form.Item>

日期中文处理

https://ant-design.gitee.io/components/date-picker-cn/

在index.js中

import React from 'react'
import ReactDOM from 'react-dom'
// 在 index.js 中导入 antd 的样式文件
import 'antd/dist/antd.css'

import './index.css'
import { ConfigProvider } from 'antd'
import 'moment/locale/zh-cn'
import locale from 'antd/lib/locale/zh_CN'

import App from './App'

ReactDOM.render(
  <ConfigProvider locale={locale}>
    <App />
  </ConfigProvider>,
  document.getElementById('root')
)

频道数据管理

  • 封装接口
import request from 'utils/request'

/*
  获取所有的频道
*/
export const getChannels = () => {
  return request.get('/channels')
}

  • 发送请求获取数据
import { getChannels } from 'api/channel'

state = {
  channels: [],
}
async getChannelList() {
  const res = await getChannels()
  this.setState({
    channels: res.data.channels,
  })
}

componentDidMount() {
  this.getChannelList()
}
  • 渲染频道数据
<Select placeholder="请选择频道" style={{ width: 200 }}>
  {this.state.channels.map((item) => (
    <Option value={item.id} key={item.id}>
      {item.name}
    </Option>
  ))}
</Select>

表格基本结构

  • 基本结构
import {
  Card,
  Breadcrumb,
  Form,
  Button,
  Radio,
  Select,
  DatePicker,
  Table,
  Tag,
  Space,
} from 'antd'

render() {
  const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
      render: (text) => <a>{text}</a>,
    },
    {
      title: 'Age',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: 'Address',
      dataIndex: 'address',
      key: 'address',
    },
    {
      title: 'Tags',
      key: 'tags',
      dataIndex: 'tags',
      render: (tags) => (
        <>
          {tags.map((tag) => {
            let color = tag.length > 5 ? 'geekblue' : 'green'
            if (tag === 'loser') {
              color = 'volcano'
            }
            return (
              <Tag color={color} key={tag}>
                {tag.toUpperCase()}
              </Tag>
            )
          })}
        </>
      ),
    },
    {
      title: 'Action',
      key: 'action',
      render: (text, record) => (
        <Space size="middle">
          <a>Invite {record.name}</a>
          <a>Delete</a>
        </Space>
      ),
    },
  ]

  const data = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park',
      tags: ['nice', 'developer'],
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park',
      tags: ['loser'],
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park',
      tags: ['cool', 'teacher'],
    },
  ]

  return (
    <div className="articleList">
      <Card title={`根据筛选条件共查询到${0}条数据`}>
        <Table dataSource={data} columns={columns} />
      </Card>
    </div>
  )
}

获取文章列表数据

  • 封装接口
import request from 'utils/request'

/**
 * 获取文章列表
 * @param {*} params
 * @returns
 */
export const getArticles = (params) => {
  return request({
    url: '/mp/articles',
    method: 'get',
    params,
  })
}

  • 发送请求获取文章列表数据
  state = {
    channels: [],
    articles: [],
    total: 0,
  }
  async getChannelList() {
    const res = await getChannels()
    this.setState({
      channels: res.data.channels,
    })
  }

  async getArticleList() {
    const res = await getArticles()
    this.setState({
      articles: res.data.results,
      total: res.data.total_count,
    })
  }

  componentDidMount() {
    this.getChannelList()
    this.getArticleList()
  }

渲染表格数据

  • 修改columns
const columns = [
  {
    title: '封面',
    dataIndex: 'name',
  },
  {
    title: '标题',
    dataIndex: 'title',
  },
  {
    title: '状态',
    dataIndex: 'status',
  },
  {
    title: '发布时间',
    dataIndex: 'pubdate',
  },
  {
    title: '阅读数',
    dataIndex: 'read_count',
  },
  {
    title: '评论数',
    dataIndex: 'comment_count',
  },
  {
    title: '点赞数',
    dataIndex: 'like_count',
  },
  {
    title: '操作',
  },
]
  • 封面处理
{
  title: '封面',
  dataIndex: 'cover',
  render(data) {
    const { images, type } = data
    if (type === 0) {
      return (
        <Image width={200} preview={false} height={150} src={defaultImg} />
      )
    }
    return (
      <Image width={200} height={150} src={images[0]} fallback={defaultImg} />
    )
  },
},
  • 状态处理
// 通过对象来优化if/switch
// 使用方式:articleStatus[0] => { text: '草稿', color: '' }
const articleStatus = {
  0: { text: '草稿', color: 'gold' },
  1: { text: '待审核', color: 'lime' },
  2: { text: '审核通过', color: 'green' },
  3: { text: '审核失败', color: 'red' },
}

{
  title: '状态',
  dataIndex: 'status',
  render: (data) => {
    const tagObj = articleStatus[data]
    return <Tag color={tagObj.color}>{tagObj.text}</Tag>
  },
},
  • 操作功能
{
    title: '操作',
    render() {
      return (
        <Space>
          <Button
            type="primary"
            shape="circle"
            icon={<EditOutlined />}
          ></Button>
          <Button
            type="primary"
            shape="circle"
            danger
            icon={<DeleteOutlined />}
          ></Button>
        </Space>
      )
    },
},

key属性处理

<Card title={`根据筛选条件共查询到${this.state.total}条数据`}>
  <Table
    rowKey="id"
    dataSource={this.state.articles}
    columns={columns}
  />
</Card>

分页功能

  • 使用分页组件
<Card title={`根据筛选条件共查询到${this.state.total_count}条数据`}>
  <Table
    rowKey="id"
    dataSource={results}
    columns={columns}
    pagination={{
      position: ['bottomCenter'],
      current: page,
      pageSize: per_page,
      total: total_count,
      // 每页大小 或者 页码 改变时,触发的事件
      onChange: this.changePage,
    }}
  />
</Card>
  • 提供changePage事件
changePage = async (page, pageSize) => {
  console.log(page)
  const res = await getArticles({
    page,
    per_page: this.state.articles.per_page,
  })
  this.setState({
    articles: res.data,
  })
}

获取表单的值进行筛选

  • 给表单注册事件
<Form initialValues={{ status: -1 }} onFinish={this.onFinish}>
  • 给表单元素提供name属性
<Form.Item label="状态" name="status">
  <Radio.Group>
    <Radio value={-1}>全部</Radio>
    <Radio value={0}>草稿</Radio>
    <Radio value={1}>待审核</Radio>
    <Radio value={2}>审核通过</Radio>
    <Radio value={3}>审核失败</Radio>
  </Radio.Group>
</Form.Item>

<Form.Item label="频道" name="channel_id">
  <Select placeholder="请选择频道" style={{ width: 200 }}>
    {this.state.channels.map((item) => (
      <Option value={item.id} key={item.id}>
        {item.name}
      </Option>
    ))}
  </Select>
</Form.Item>

<Form.Item label="日期" name="date">
  <RangePicker />
</Form.Item>
  • 发送请求,获取数据
onFinish = async (values) => {
  console.log(values)
  // 发送请求,获取数据
  const params = {}
  // 处理状态
  if (values.status !== -1) {
    params.status = values.status
  }
  // 处理频道
  if (values.channel_id) {
    params.channel_id = values.channel_id
  }
  // 处理日期
  if (values.date) {
    params.begin_pubdate = values.date[0].format('YYYY-MM-DD')
    params.end_pubdate = values.date[1].format('YYYY-MM-DD')
  }
  params.page = 1
  const res = await getArticles(params)
  console.log(res.data)
  this.setState({
    articles: res.data,
  })
}

时间的优化

// 处理日期
if (values.date) {
  params.begin_pubdate = values.date[0]
    .startOf('day')
    .format('YYYY-MM-DD HH:mm:ss')
  params.end_pubdate = values.date[1]
    .endOf('day')
    .format('YYYY-MM-DD HH:mm:ss')
}

修改分页bug

changePage = async (page, pageSize) => {
  const res = await getArticles({
    ...this.params,
    page,
    per_page: this.state.articles.per_page,
  })
  this.setState({
    articles: res.data,
  })
}
onFinish = async (values) => {
  console.log(values)
  // 发送请求,获取数据
  const params = {}
  // 处理状态
  if (values.status !== -1) {
    params.status = values.status
  }
  // 处理频道
  if (values.channel_id) {
    params.channel_id = values.channel_id
  }
  // 处理日期
  if (values.date) {
    params.begin_pubdate = values.date[0]
      .startOf('day')
      .format('YYYY-MM-DD HH:mm:ss')
    params.end_pubdate = values.date[1]
      .endOf('day')
      .format('YYYY-MM-DD HH:mm:ss')
  }
  params.page = 1
  this.params = params
  const res = await getArticles(params)
  console.log(res.data)
  this.setState({
    articles: res.data,
  })
}

删除功能

  • 注册点击事件
<Button
  type="primary"
  shape="circle"
  danger
  icon={<DeleteOutlined />}
  onClick={() => this.handleDelete(data.id)}
></Button>
  • 准备弹窗
handleDelete = (id) => {
  confirm({
    title: '温馨提示?',
    icon: <ExclamationCircleOutlined />,
    content: '你确定要删除文章吗',
    onOk() {
      // 发送请求进行删除
    },
  })
}
  • 封装接口进行删除
/**
 * 删除文章
 * @param {*} id
 * @returns
 */
export const delArticle = (id) => {
  return request({
    url: `/mp/articles/${id}`,
    method: 'delete',
  })
}

  • 删除功能完成
handleDelete = (id) => {
  confirm({
    title: '温馨提示?',
    icon: <ExclamationCircleOutlined />,
    content: '你确定要删除文章吗',
    onOk: async () => {
      // 发送请求进行删除
      await delArticle(id)
      this.getArticleList(this.params)
    },
  })
}

发布文章

基本结构准备

  • 面包屑
import React, { Component } from 'react'
import { Card, Breadcrumb } from 'antd'
import { Link } from 'react-router-dom'
export default class ArticleList extends Component {
  render() {
    return (
      <div className="ArticleList">
        <Card
          title={
            <Breadcrumb separator=">">
              <Breadcrumb.Item>
                <Link to="/home">首页</Link>
              </Breadcrumb.Item>
              <Breadcrumb.Item>发布文章</Breadcrumb.Item>
            </Breadcrumb>
          }
        ></Card>
      </div>
    )
  }
}
  • 表单
import { Card, Breadcrumb, Form, Input, Radio, Space, Button } from 'antd'

<Form labelCol={{ span: 4 }} initialValues={{ type: 0 }}>
  <Form.Item label="标题" name="title">
    <Input placeholder="请输入文章标题" style={{ width: 400 }} />
  </Form.Item>
  <Form.Item label="频道" name="channel_id">
    频道组件
  </Form.Item>
  <Form.Item label="封面">
    <Form.Item name="type">
      <Radio.Group onChange={this.changeImageType}>
        <Radio value={0}>无图</Radio>
        <Radio value={1}>单图</Radio>
        <Radio value={3}>三图</Radio>
        {/* <Radio value={-1}>自动</Radio> */}
      </Radio.Group>
    </Form.Item>
    图片上传组件
  </Form.Item>
  <Form.Item label="内容" name="content">
    文章内容
  </Form.Item>
  <Form.Item wrapperCol={{ offset: 4 }}>
    <Space>
      <Button size="large" type="primary" htmlType="submit">
        发布文章
      </Button>
      <Button size="large">存入草稿</Button>
    </Space>
  </Form.Item>
</Form>
  • 给表单注册事件
<Form
  labelCol={{ span: 4 }}
  initialValues={{ type: 0 }}
  onFinish={this.onFinish}
>


onFinish = (values) => {
  console.log(values)
}

频道组件封装

  • 基础封装
import { Component } from 'react'
import { Select } from 'antd'
import { getChannels } from 'api/channel'

const { Option } = Select

class Channel extends Component {
  state = {
    channels: [],
  }

  componentDidMount() {
    this.getChannles()
  }

  // 获取频道列表数据的方法
  async getChannles() {
    const res = await getChannels()
    this.setState({
      channels: res.data.channels,
    })
  }

  render() {
    const { channels } = this.state

    return (
      <Select placeholder="请选择文章频道">
        {channels.map((item) => (
          <Option key={item.id} value={item.id}>
            {item.name}
          </Option>
        ))}
      </Select>
    )
  }
}

export default Channel

  • 使用频道组件
import Channel from 'components/Channel'

<Form.Item label="频道" name="channel_id">
  <Channel></Channel>
</Form.Item>
  • 让频道组件受控

参考文档:https://ant-design.gitee.io/components/form-cn/#components-form-demo-customized-form-controls

render() {
  const { channels } = this.state
  const { value, onChange } = this.props
  return (
    <Select
      placeholder="请选择文章频道"
      style={{ width: 200 }}
      value={value}
      onChange={onChange}
    >
      {channels.map((item) => (
        <Option key={item.id} value={item.id}>
          {item.name}
        </Option>
      ))}
    </Select>
  )
}

文章内容处理

import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

<Form.Item label="内容" name="content">
  <ReactQuill
    theme="snow"
    placeholder="请输入文章内容..."
  ></ReactQuill>
</Form.Item>
  • 注意:必须提供默认值,不然会报错
  • 提供样式
.publish {
  :global {
    .ql-editor {
      min-height: 300px;
    }
  }
}

图片上传组件

  • 基本结构
import {
  Card,
  Breadcrumb,
  Form,
  Input,
  Radio,
  Space,
  Button,
  Upload,
} from 'antd'
import { PlusOutlined } from '@ant-design/icons'

<Upload listType="picture-card">
  <PlusOutlined></PlusOutlined>
</Upload>
  • 设置图片默认显示
<Upload
  listType="picture-card"
  name="image"
  fileList={this.state.fileList}
>
  <PlusOutlined></PlusOutlined>
</Upload>


state = {
  // 存放上传的文件列表
  fileList: [
    {
      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    },
    {
      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    },
  ],
}

  • 图片上传功能, 需要提供name和action参数
<Upload
  listType="picture-card"
  name="image"
  action={`${baseURL}upload`}
  onChange={this.uploadImages}
  fileList={this.state.fileList}
>
  <PlusOutlined></PlusOutlined>
</Upload>
  • 获取上传成功的图片地址
uploadImages = ({ file, fileList }) => {
  this.setState({
    fileList,
  })
}

控制图片的上传数量

  • 控制type的切换
state = {
  // 存放上传的文件列表
  fileList: [],
  type: 0,
}

<Radio.Group onChange={this.changeImageType}>
  <Radio value={0}>无图</Radio>
  <Radio value={1}>单图</Radio>
  <Radio value={3}>三图</Radio>
</Radio.Group>


changeImageType = (e) => {
  this.setState({
    type: e.target.value,
  })
}
  • 根据type控制图片的显示
{this.state.type !== 0 && (
  <Upload
    listType="picture-card"
    name="image"
    action={`${baseURL}upload`}
    onChange={this.uploadImages}
    fileList={this.state.fileList}
  >
    <PlusOutlined></PlusOutlined>
  </Upload>
)}
  • 控制图片的上传数据
{this.state.type !== 0 && (
  <Upload
    listType="picture-card"
    name="image"
    action={`${baseURL}upload`}
    onChange={this.uploadImages}
    fileList={this.state.fileList}
  >
    {this.state.fileList.length < this.state.type && (
      <PlusOutlined></PlusOutlined>
    )}
  </Upload>
)}

图片预览功能

图片格式校验

表单校验功能

  • 表单基本校验
<Form.Item
  label="标题"
  name="title"
  rules={[{ required: true, message: '请输入文章标题' }]}
>
  <Input placeholder="请输入文章标题" style={{ width: 400 }} />
</Form.Item>
<Form.Item
  label="频道"
  name="channel_id"
  rules={[{ required: true, message: '请选择文章频道' }]}
>
  <Channel></Channel>
</Form.Item>
<Form.Item label="封面">
  <Form.Item name="type">
    <Radio.Group onChange={this.changeImageType}>
      <Radio value={1}>单图</Radio>
      <Radio value={3}>三图</Radio>
      <Radio value={0}>无图</Radio>
      {/* <Radio value={-1}>自动</Radio> */}
    </Radio.Group>
  </Form.Item>
  <div className="upload-list">
    {this.state.type !== 0 && (
      <Upload
        listType="picture-card"
        name="image"
        action={`${baseURL}upload`}
        onChange={this.uploadImages}
        fileList={this.state.fileList}
      >
        {this.state.fileList.length < this.state.type && (
          <PlusOutlined></PlusOutlined>
        )}
      </Upload>
    )}
  </div>
</Form.Item>
<Form.Item
  label="内容"
  name="content"
  rules={[{ required: true, message: '请输入文章内容' }]}
>
  <ReactQuill
    theme="snow"
    placeholder="请输入文章内容..."
  ></ReactQuill>
</Form.Item>
  • 图片长度的校验
onFinish = async (values) => {
  // 图片校验
  if (this.state.type !== this.state.fileList.length) {
    return message.warn('上传的图片数量不对')
  }
}

发送请求-添加文章

  • 封装接口
/**
 * 发送请求添加文章
 * @param {*} data
 * @returns
 */
export const addArticle = (data) => {
  return request({
    url: '/mp/articles',
    method: 'post',
    data,
  })
}

  • 发送请求-处理数据并且添加文章
onFinish = async (values) => {
  console.log(values)
  // 处理数据,添加文章
  const images = this.state.fileList.map((item) => {
    if (item.url) {
      return item.url
    }
    return item.response.data.url
  })
  const res = await addArticle({
    ...values,
    cover: {
      type: values.type,
      images,
    },
  })
  message.success('添加文章成功')
  this.props.history.push('/home/list')
}

存入草稿功能

  • 修改接口
/**
 * 发送请求添加文章
 * @param {*} data
 * @returns
 */
export const addArticle = (data, draft = false) => {
  return request({
    url: '/mp/articles?draft=' + draft,
    method: 'post',
    data,
  })
}
  • 注册点击事件
<Button size="large" onClick={this.addDraft}>
  存入草稿
</Button>
  • 提供事件
  onFinish = async (values) => {
    this.save(values, false)
  }
  save = async (values, draft) => {
    // 图片校验
    if (this.state.type !== this.state.fileList.length) {
      return message.warn('上传的图片数量不对')
    }
    // 处理数据,添加文章
    const images = this.state.fileList.map((item) => {
      if (item.url) {
        return item.url
      }
      return item.response.data.url
    })
    await addArticle(
      {
        ...values,
        cover: {
          type: values.type,
          images,
        },
      },
      draft
    )
    message.success('添加文章成功')
    this.props.history.push('/home/list')
  }
  addDraft = async () => {
    // 获取表单的数据
    const values = await this.formRef.current.validateFields()
    this.save(values, true)
  }

修改功能

配置修改文章的路由

  • 给修改按钮注册点击事件
<Button
  type="primary"
  shape="circle"
  icon={<EditOutlined />}
  onClick={() => this.handleEdit(data.id)}
/>

// 修改
handleEdit = (id) => {
  this.props.history.push(`/home/publish/${id}`)
}
  • 配置修改文章的路由
{/* 新增 */}
<Route
  exact
  path="/home/publish"
  component={ArticlePublish}
></Route>
{/* 修改的路由 */}
<Route
  path="/home/publish/:id"
  component={ArticlePublish}
></Route>

数据回显-获取数据

思路

  1. 在组件中判断能够通过params获取到id值,如果能够获取到id,说明是修改,如果获取不到id说明是新增
  2. 我们根据是否是新增可以修改对应的文本。【发布文章】或者【修改文章】
  3. 封装接口,用于获取文章的详情信息
  4. 发送请求,获取文章的详细信息
  • 获取地址栏的id值
state = {
  // 文章的封面类型
  type: 1,
  // 用于控制上传的图片以及图片的显示
  fileList: [],
  showPreview: false,
  previewUrl: '',
  // 编辑的id
+  id: this.props.match.params.id,
}
  • 根据是否有id值,控制文本的显示
{id ? '编辑文章' : '发布文章'}
  • 封装接口,获取文章详情
/**
 * 获取文章详情信息
 * @param {*} id
 * @returns
 */
export const getArticleById = (id) => {
  return request.get(`/mp/articles/${id}`)
}
  • 页面渲染完成的时候,发送请求-获取数据
async componentDidMount() {
  if (this.state.id) {
    // 需要发请求,获取文章详细信息
    const res = await getArticleById(this.state.id)
    console.log('res', res)
  }
}

数据回显-回显数据

思路:

  1. 通过Form组件提供的方法 setFieldsValue 可以给表单设置值
  2. 设置fileList的值,fileList控制封面显示的
  • 设置表单的值
async componentDidMount() {
  if (this.state.id) {
    // 需要发请求,获取文章详细信息
    const res = await getArticleById(this.state.id)
    const values = {
      ...res.data,
      type: res.data.cover.type,
    }
    // 给表单设置values值
    this.formRef.current.setFieldsValue(values)
    const fileList = res.data.cover.images.map((item) => {
      return {
        url: item,
      }
    })
    this.setState({
      fileList,
    })
  }
}

修复bug-修改切换到新增的bug

{/* 新增 */}
<Route
  exact
  path="/home/publish"
  component={ArticlePublish}
  key="add"
></Route>
{/* 修改的路由 */}
<Route
  path="/home/publish/:id"
  component={ArticlePublish}
  key="edit"
></Route>

修改功能完成

  1. 封装接口,用于修改文章
  2. 判断是否有id,如果有,发送请求修改,否则,发送请求新增
  • 封装接口


/**
 * 修改文章的接口
 * @param {*} data
 * @param {*} draft
 * @returns
 */
export const updateArticle = (data, draft) => {
  return request({
    url: `/mp/articles/${data.id}?draft=${draft}`,
    method: 'PUT',
    data,
  })
}

  • 判断
async save(values, draft) {
  const { fileList, type } = this.state
  if (fileList.length !== type) {
    return message.warn('上传的图片数量不正确')
  }
  // 根据fileList得到
  const images = fileList.map((item) => {
    return item.url || item.response.data.url
  })
  if (this.state.id) {
    // 修改文章
    await updateArticle(
      {
        ...values,
        cover: {
          type,
          images,
        },
        id: this.state.id,
      },
      draft
    )
    message.success('修改成功')
  } else {
    // 添加文章
    await addAritcle(
      {
        ...values,
        cover: {
          type,
          images,
        },
      },
      draft
    )
    message.success('添加成功')
  }
  this.props.history.push('/home/list')
}

导航高亮优化

  • 给菜单按钮提供selectedKeys属性
<Menu
  theme="dark"
  mode="inline"
  selectedKeys={[this.state.selectedKey]}
  style={{ height: '100%', borderRight: 0 }}
>
    
state = {
  profile: {},
  selectedKey: this.props.location.pathname,
}
  • 需要在组件更新的时候,修改selectedKeys的值
// 组件更新完成的钩子函数,,,路由变化了,组件也是会重新渲染
// prevProps: 上一次的props
componentDidUpdate(prevProps) {
  // 判断是否是url地址发生了变化,如果是,才更新
  let pathname = this.props.location.pathname
  if (this.props.location.pathname !== prevProps.location.pathname) {
    // 考虑修改文章的高亮问题
    if (pathname.startsWith('/home/publish')) {
      pathname = '/home/publish'
    }
    this.setState({
      selectedKey: pathname,
    })
  }
}

注意:在componentDidUpdate中想要调用setState必须添加判断,不然会死循环

posted @ 2022-03-24 16:15  小沈曰  阅读(172)  评论(0编辑  收藏  举报