Skip to content

手写antd提示组件

1. 功能需求

支持成功和提示类型的消息展示,可以连续弹出,并隔2秒消失。

2. 代码实现

jsx
import './JKMessage.css'
import { InfoCircleFilled, CheckCircleFilled } from '@ant-design/icons'
import { createRoot } from 'react-dom/client'
import PropTypes from 'prop-types'

function JKMessage({ msg = '', icon = null }) {
  return (
    <div className="jk-ant-message-notice">
      <div className="jk-ant-message-notice-content">{icon} {msg}</div>
    </div>
  )
}

const jkMessage = {
  wrapper: null,
  root: null,
  list: [],
  showAndHide(msg, icon) {
    // 有root需要提前卸载
    if (this.root) {
      this.root.unmount()
      this.root = null
    }
    // 创建消息挂载DOM位置
    if (!this.wrapper) {
      this.wrapper = document.createElement('div')
      this.wrapper.className = 'jk-ant-message'
      document.body.appendChild(this.wrapper)
    }
    if (!this.root) {
      // root不能多次创建,否则会报错
      this.root = createRoot(this.wrapper)
      this.list.push(
        <JKMessage key={this.list.length} msg={msg} icon={icon} />
      )
      this.root.render(this.list)
    }

    setTimeout(() => {
      // 一个一个消息挨个清除
      this.list.shift()
      this.root = null
      this.wrapper.children[0].remove()
      // 如果wrapper里面已经清除完毕所有消息,就清楚wrapper
      if (this.list.length === 0) {
        this.wrapper.remove()
        this.wrapper = null
      }
    }, 2000)
  },
  info(msg) {
    this.showAndHide(msg, <InfoCircleFilled style={{ color: 'blue' }} />)
  },
  success(msg) {
    this.showAndHide(msg, <CheckCircleFilled style={{ color: 'green' }} />)
  }
}
JKMessage.propTypes = {
  msg: PropTypes.string,
  icon: PropTypes.element
}
export default jkMessage
css
.jk-ant-message {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    color: rgba(0, 0, 0, 0.88);
    font-size: 14px;
    line-height: 1.5714285714285714;
    list-style: none;
    font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';
    position: fixed;
    top: 8px;
    width: 100%;
    pointer-events: none;
    z-index: 1010;
    left: 50%;
    transform: translateX(-50%);
    top: 8px;
}
.jk-ant-message-notice {
    padding: 8px;
    text-align: center;
}
.jk-ant-message-notice-content {
    display: inline-block;
    padding: 9px 12px;
    background: #ffffff;
    border-radius: 8px;
    box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
    pointer-events: all;
}
js
import JKButton from './JKButton/JKButton.jsx'
import JKRate from './JKRate/JKRate.jsx'
import jkMessage from './JKMessage/JKMessage.jsx'

export  {JKButton, JKRate, jkMessage}
jsx
import { Button, message, Space } from 'antd'
import {jkMessage} from './JKAntd'

function App() {
  const handleClick1 = () => {
    message.info('hello Antd! ')
  }
  const handleClick2 = () => {
    message.success("操作成功!")
  }
  const handleClick3 = () => {
    jkMessage.info('hello Antd! ')
  }
  const handleClick4 = () => {
    jkMessage.success("操作成功!")
  }
  return (
    <>
      hello App
      <br />
      <br />
      <Space>
        <Button type="primary" onClick={handleClick1}>点击1</Button>
        <Button type="primary" onClick={handleClick2}>点击2</Button>
      </Space>
      <br />
      <br />
      <Space>
        <Button type="primary" onClick={handleClick3}>点击1</Button>
        <Button type="primary" onClick={handleClick4}>点击2</Button>
      </Space>
    </>
  )
}
export default App

运行效果:
Alt text