📅 GJ504b 的 React 进阶之路:Day 4

📅 GJ504b 的 React 进阶之路:Day 4

今日立春
我们清空冗余缓存,期待 2026 的每一份装载
今天学习的 antd 的一些组件的使用方法

1 Button 与 Icon

按钮是触发交互的基础,通过属性配置可实现复杂的状态反馈。

技术要点

  • type="primary"danger:属性解耦,danger 可独立应用于任何类型的按钮。
  • icon={<IconName />}:将图标组件作为属性传入。
  • loading={bool}:绑定状态变量,实现异步处理时的视觉反馈与点击禁用。
  • htmlType="submit":在表单内部使用,用于关联表单的提交事件。

alt text
点击图标加载,3s 后恢复
alt text


<Button
  type='primary'
 {/* 1. danger是一个独立的属性 而不是在type里 */}
  danger
  icon={<SearchOutlined />}
  loading={loading}
  onClick={clickButton}
>
  加载中……
</Button>

 {/* 2. 绑定点击事件和loading状态 */}
  const [loading, setLoadings] = useState(false);
  const clickButton = () => {
    setLoadings(true);
    setTimeout(() => {
      setLoadings(false);
    }, 3000);
    // 3秒后loading状态变成false
  };

2 message(全局提示)

Ant Design 5.0 推荐使用 Hooks 方式调用,以保证样式的一致性和上下文的完整性。

技术要点

  • useMessage():解构出 messageApi(操作对象)和 contextHolder(渲染容器)。
  • {contextHolder}:必须写在 JSX 的根部,否则提示信息无法渲染。

alt text

const [messageApi, contextHolder] = message.useMessage(); //4. 引入message统一格式

const clickButton = () => {
  setLoadings(true);
  setTimeout(() => {
    setLoadings(false);
    messageApi.info("搜索完成,找到0个相关患者"); //4. 引入message统一格式,info()方法,里面写要输出的内容
  }, 3000);
};

// 渲染参考:
return (
  <Flex vertical>
    {contextHolder}
    {/* 4. 引入message统一格式,必须写 */}

    <Button onClick={clickButton}>触发提示</Button>
  </Flex>
);

3 Modal(对话框)

Modal 不仅是容器,其在 HTML 结构中的位置直接影响系统的稳定性。

为什么 Modal 与 Button 必须是兄弟结构(平级)?

  1. HTML 容积限制<button> 是行内块级元素,无法合规承载 Modal 复杂的 div 嵌套结构。
  2. 冒泡效应(Event Bubbling):若嵌套,点击弹窗内的按钮会向上传递至父级按钮,引发逻辑死循环。
  3. Portal 传送门机制:Antd 底层会将 Modal 渲染至 <body> 根部,保持代码平级更符合实际渲染物理结构。

属性应用

  • footer={null}:移除默认的“确定/取消”按钮,由内部表单控制提交。

alt text
alt text


{/* 5. Modal与Button是同级的 */}
{/* 为什么不是父子结构:① HTML 的“肚量”有限
在网页的最底层,<button> 标签是一个行内块级元素,它只能装着文字、图标或者少量的修饰标签。

Modal 的本质:它包含了遮罩层、标题、内容区、页脚按钮……这其实是一大堆嵌套的 <div>。

后果:把一整栋楼(Modal)塞进一个信箱(Button)里,会导致浏览器解析出错,样式会变得乱七八糟。

② “冒泡”效应 (Event Bubbling)
这是最麻烦的一点。在 JS 中,事件会向上冒泡:

如果你把 Modal 放在 Button 里面,当你点击 Modal 里的“确定”按钮时,浏览器可能会认为你同时也点击了外层的 Button。

死循环:这可能导致你刚想关掉弹窗,它又被外层的按钮触发重新打开了。

③ 传送门逻辑 (Portals)
Ant Design 的 Modal 看起来是在你点击的地方弹出来的,但实际上为了不被父元素的样式(比如 overflow: hidden)遮挡,它在底层利用了 React 的 Portal(传送门) 技术,把自己偷偷渲染到了 HTML 的 <body> 最底部。

所以,哪怕你在代码里把它写在按钮里,它最终也会“飞”到别的地方去。既然如此,为了代码整洁,我们干脆就让它们并列排放。 */}
<Button onClick={opening}>want to say sth to u</Button>

<Modal onCancel={isCancel} onOk={isOk} open={isOpen}>
{/* onCancel,onOk,open属性,当open属性true则显示,而button绑定切换open功能 */}
<p>Happy New Year!</p>
</Modal>


const [isOpen, setIsOpen] = useState(false);
const opening = () => {
setIsOpen(true);
};
const isOk = () => {
setIsOpen(false);
};
const isCancel = () => {
setIsOpen(false);
};

4 Form 与 Input

表单是 B 端系统的灵魂,负责数据的采集、验证与上报。

技术要点

  • onFinish:提交触发的回调函数,其参数 value 是一个包含所有字段的对象。
  • Form.Itemname:定义数据键名。
  • rules:前端校验逻辑,required: true 实现非空约束。
  • 调试建议:使用 console.log("提示语", value) 而非模板字符串,以保留对象的交互检查特性。
    alt text
    alt text
    alt text


<Button type="primary" style={{width:'20%'}} onClick={formAdd}>添加姓名</Button>
<Modal open={form} footer={null}>
{/* footer={null}:去掉Modal默认的下部分(取消,ok) */}
    <h2>患者登记表</h2>
    <Form layout="vertical" onFinish={onFinish} >
    <Form.Item label="姓名" name="username" rules={[{required:true,message:'请输入您的姓名'}]}>
        <Input type="text" placeholder="请输入您的姓名" />
    
    </Form.Item>
    <Form.Item >
        <Button type="primary" htmlType='submit'>立即登记</Button>
    </Form.Item>
    </Form>
</Modal>


  const onFinish = (value)=>{
    // console.log(`已经收到${value}`)
    // 打印一句话用 ${},检查一个对象用 逗号
    console.log("你拿到了数据",value)
    message.success(`成功录入:${value.username}`)
    setFrom(false)
  }


  const [form,setFrom] = useState(false)
  const formAdd =()=>{
    setFrom(true)
  }

5 完整代码

import React, { useState } from "react";
import { SearchOutlined } from "@ant-design/icons"; //引入icon库
import { Button, Flex, message, Modal,Form,Input } from "antd";
import useMessage from "antd/es/message/useMessage";
const App = () => {
  const [loading, setLoadings] = useState(false);
  const clickButton = () => {
    setLoadings(true);
    setTimeout(() => {
      setLoadings(false);
      messageApi.info("搜索完成,找到0个相关患者"); //4. 引入message统一格式,info()方法,里面写要输出的内容
    }, 3000);
    //2. 3秒后loading状态变成false
  };
  const [messageApi, contextHolder] = message.useMessage(); //4. 引入message统一格式

  const [isOpen, setIsOpen] = useState(false);
  const opening = () => {
    setIsOpen(true);
  };
  const isOk = () => {
    setIsOpen(false);
  };
  const isCancel = () => {
    setIsOpen(false);
  };


  const onFinish = (value)=>{
    // console.log(`已经收到${value}`)
    // 打印一句话用 ${},检查一个对象用 逗号
    console.log("你拿到了数据",value)
    message.success(`成功录入:${value.username}`)
    setFrom(false)
  }


  const [form,setFrom] = useState(false)
  const formAdd =()=>{
    setFrom(true)
  }
  return (
    <Flex gap='small' vertical>
      {contextHolder}
      {/* 4. 引入message统一格式,必须写 */}

      <Button type='primary' danger icon={<SearchOutlined />} loading>
        加载中……
      </Button>
      {/* 1. danger是一个独立的属性 而不是在type里 */}
      <Button
        type='primary'
        danger
        icon={<SearchOutlined />}
        loading={loading}
        onClick={clickButton}
      >
        加载中……
      </Button>
      {/* 3. 绑定点击事件和loading状态 */}

{/* 5. Modal与Button是同级的 */}
{/* 为什么不是父子结构:① HTML 的“肚量”有限
在网页的最底层,<button> 标签是一个行内块级元素,它只能装着文字、图标或者少量的修饰标签。

Modal 的本质:它包含了遮罩层、标题、内容区、页脚按钮……这其实是一大堆嵌套的 <div>。

后果:把一整栋楼(Modal)塞进一个信箱(Button)里,会导致浏览器解析出错,样式会变得乱七八糟。

② “冒泡”效应 (Event Bubbling)
这是最麻烦的一点。在 JS 中,事件会向上冒泡:

如果你把 Modal 放在 Button 里面,当你点击 Modal 里的“确定”按钮时,浏览器可能会认为你同时也点击了外层的 Button。

死循环:这可能导致你刚想关掉弹窗,它又被外层的按钮触发重新打开了。

③ 传送门逻辑 (Portals)
Ant Design 的 Modal 看起来是在你点击的地方弹出来的,但实际上为了不被父元素的样式(比如 overflow: hidden)遮挡,它在底层利用了 React 的 Portal(传送门) 技术,把自己偷偷渲染到了 HTML 的 <body> 最底部。

所以,哪怕你在代码里把它写在按钮里,它最终也会“飞”到别的地方去。既然如此,为了代码整洁,我们干脆就让它们并列排放。 */}


      <Button onClick={opening}>want to say sth to u</Button>
      <Modal onCancel={isCancel} onOk={isOk} open={isOpen}>
        {/* onCancel,onOk,open属性,当open属性true则显示,而button绑定切换open功能 */}
        <p>Happy New Year!</p>

      </Modal>

      <Button type="primary" style={{width:'20%'}} onClick={formAdd}>添加姓名</Button>
      <Modal open={form} footer={null}>
        {/* footer={null}:去掉Modal默认的下部分(取消,ok) */}
      <h2>患者登记表</h2>
      <Form layout="vertical" onFinish={onFinish} >
        <Form.Item label="姓名" name="username" rules={[{required:true,message:'请输入您的姓名'}]}>
          <Input type="text" placeholder="请输入您的姓名" />

        </Form.Item>
        <Form.Item >
          <Button type="primary" htmlType='submit'>立即登记</Button>
        </Form.Item>
      </Form>
      </Modal>

    </Flex>
  );
};
export default App;



重温第二天力扣

做一半力扣在维修,只好明天了
alt text

/**
 * @param {string[]} strs
 * @return {string[][]}
 */
var groupAnagrams = function (strs) {
  const map = new Map();

  for (let str of strs) {
    let arr = Array.from(str);
    // arr.sort((a, b) => a - b)//这里是字符排序,不可以,这个是数字排序
    //法1:直接sort(),Unicode就是字符排序
    // arr.sort()
    //法2:a.localeCompare(b) 是字符串的原生方法,专门用于字符串的字典序比较,返回值是数字(-1/0/1)
    arr.sort((a, b) => a.localeCompare(b));
    let key = arr.toString();
    let list = map.get(key) ? map.get(key) : new Array();
    list.push(str);
    map.set(key, list);
  }
  return Array.from(map.values());
};
posted @ 2026-02-04 22:14  GJ504b  阅读(0)  评论(0)    收藏  举报