#说明

antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。也是是本人目前实习公司所用框架技术之一

本笔记主要记录工作中项目中遇到的与官方文档有差异化的 的使用方式、或者是自己对于文档记录的组件的使用,方便自己查阅

除此笔记外大家可以看我其他笔记 :全栈笔记数据结构与算法编程_前端开发学习笔记编程_后台服务端学习笔记JavaNodejsJavaScript笔记ES6及后续版本学习笔记Vue笔记整合React笔记微信小程序学习笔记Chrome开发使用及学习笔记 以及许多其他笔记就不一一例举了

#目录

Ant Design of React 文档

  1. 官方文档地址
  2. 组件

一、数据录入

1、From表单

许多数据录入是与From表单相结合的

Ⅰ- 限制表单中输入框不能为空以及中文

  1. 通过[From.Item](https://ant.design/components/form-cn/#Form.Item) 中的 normalize属性进行处理对value的处理:组件获取值后进行转换,再放入 Form 中。不支持异步
  2. 通过正则替换,将键入的空格以及中文替换为空字符串
  3. 代码示例
  1. <Form form={form} onFinish={handleFinish}>
  2. <Item
  3. label="密码"
  4. name="password"
  5. rules={[{ required: true, message: '密码不能为空' }]}
  6. //密码框不允许为空格,且不允许输入中文
  7. normalize={(value) => value.replace(/\s/g, '').replace(/[\u4E00-\u9FA5]|[\uFE30-\uFFA0]/gi, '')
  8. }
  9. >
  10. <Input.Password
  11. placeholder="请输入密码"
  12. autoComplete="new-password"
  13. />
  14. </Item>
  15. </From>

Ⅱ - 自定义校验

  1. 详见[Rule](https://ant.design/components/form-cn/#Rule)属性中自定义validator
  2. 通常用作用户名等校验
  1. 通常用作必须字段校验(不进行数据库查询)
  1. <Form form={form} onFinish={handleFinish}>
  2. <Item
  3. label="用户名"
  4. name="username"
  5. validateTrigger="onBlur"
  6. normalize={(value) => value.replace(/\s/g, '')}
  7. rules={[
  8. //此处message为空字符串是为了防止下方自定义校验返回的字符串重叠
  9. { required: true, message: '' },
  10. {
  11. validator: async (_, value) => {
  12. //如果是修改时,可以用这句话,当你内容没改变时,不进行校验
  13. if (editData.name === value) return;
  14. //判断空以及输入空字符串的报错
  15. if (value == null || value.trim() == '') return Promise.reject("用户名不能为空");
  16. //请求接口,查询通过上述两个校验后的字符串是否与数据库中重复,如果重复,则提示用户名已存在
  17. const res: IResult<IExist> = await ChannelApi.isUserExist( value );
  18. if (res?.data.status) return Promise.reject('用户名已存在');
  19. else return Promise.resolve();
  20. },
  21. },
  22. ]}
  23. >
  24. <Input placeholder="请输入用户名" />
  25. </Item>
  26. </From>
  1. <Item
  2. label="必填项"
  3. name="incomeType"
  4. rules={[
  5. { required: true, message: '' },
  6. {
  7. validator: async (_, value) => {
  8. if (value == null || value.trim() == '')
  9. return Promise.reject('必填项不能为空');
  10. },
  11. },
  12. ]}
  13. >
  14. <Input.TextArea placeholder="请输入必填项信息" />
  15. </Item>

Ⅲ - 表单中动态修改数字输入框的value

  1. 出现场景:在 第一次对[InputNumber](https://ant.design/components/input-number-cn/#API)组件输入0时,就自动填充为设置的min了,这时我的需求是改成输入框失去焦点时再自动填充为min
  2. 用到的组件:From[InputNumber](https://ant.design/components/input-number-cn/#API)
  3. 代码示例
  1. //最小折扣,用于动态改变最小折扣
  2. const [min, setMin] = useState(0);
  3. <Form form={form} onFinish={handleFinish}>
  4. <Item
  5. label="折扣数"
  6. name="discount"
  7. rules={[{ required: true, message: '推荐码折扣不能为空' }]}
  8. >
  9. <InputNumber
  10. style={{ width: '100%' }}
  11. placeholder={DISCOUNT_TIP}
  12. // min={0.9}
  13. min={min}
  14. max={1}
  15. step={0.01}
  16. precision={2}
  17. // 第一次输入推荐码折扣,输入0,就自动填充为0.9了,建议改成输入框失去焦点时再自动填充为0.9
  18. //所以取消默认min,通过动态添加min实现第一次不会自动填充,唯有失去焦点时才会执行
  19. onBlur={(e) => {
  20. if (Number(e.target.value) < 0.9) form.setFieldsValue({ discount: 0.9 })
  21. setMin(0.9)
  22. }}
  23. />
  24. </Item>
  25. </From>

Ⅳ - 限制表单中输入框-不能只输入纯空格以及为空(保留value中间空格)

  1. 出现场景:详见截图

    AntDesign_ofReact使用笔记 - 图1

  2. 代码示例:此处指举例第一个输入框,并在里面进行注释
  1. 解析
    1. rulesmessage为什么要置空?
      因为下方value == null就是为空提示,不置空会出现提示两遍的错误
    2. 为什么下方validator中已经给出为空提示,为何还要保留{ required: true, message: '' }?
      因为需要输入框前有提示必填 如果不是必填项就不需要,此项会给你增加``号标识
    3. 为何不直接给输入内容.trim()去除前后空格?
      因为输入监听导师value是单次输入,需要你在后面提交时将参数进行一次trim()去除前后空格
  1. <Form {...FORM_LAYOUT} form={form} onFinish={handleFinish}>
  2. <Item
  3. label="xxx名"
  4. name="name"
  5. validateTrigger="onBlur"
  6. // normalize={(value) => value.replace(/\s/g, '')} //此行代码是直接限制无法输入空格,不符需求所以废弃
  7. rules={[
  8. //1. 此处message要置空,因为下方`value == null `就是为空提示,不置空会出现提示两遍的错误
  9. //2. 为何保留此处? 需要输入框前有*提示必填 如果不是必填项就不需要
  10. { required: true, message: '' },
  11. {
  12. validator: async (_, value) => {
  13. //此行是去除前后空格后为空字符串或者直接为空的话返回 不能为空提示
  14. if (value == null ||value.trim() == '') {
  15. return Promise.reject('xxx名不能为空');
  16. } else {
  17. const res: IResult<IExist> = await ChannelApi.isChannelExist(
  18. value
  19. );
  20. if (res?.data.status) {
  21. return Promise.reject('xxx名已存在');
  22. } else {
  23. return Promise.resolve();
  24. }
  25. }
  26. },
  27. },
  28. ]}
  29. >
  30. <Input placeholder="请输入渠道商名" />
  31. </Item>
  32. //不是必须项的对比
  33. <Item label="联系人" name="contactName">
  34. <Input placeholder="请输入联系人" />
  35. </Item>
  36. </Form>

Ⅴ - 实现嵌套结构-多类型输入效果

  1. 需求场景:当要求通过下拉框切换后面输入框类别,同时后面的输入框绑定的值不同(与文档中给出的不同:文档中后续输入框时同一个,只是简单时输入框组合)
  2. 需求示例截图

AntDesign_ofReact使用笔记 - 图2

  1. 实现思路:
  • Form.Item中再嵌套Form.Item,然后将各自规则分开写(不能写在父item中).分别绑定不同变量名,通过选择的类型切换渲染后面的Form.Item
  • 在取数据时,可以判断其中一个变量为空时进行对另一个变量的数据(如果不渲染Form.Item,其绑定的变量为undefined),如此就能实现此需求
  • 此处记录主要起到借鉴作用,我感觉应有更好的写法,但是暂时没想出,同学们如果有好写法希望可以提出交流
  1. 解决代码:
  1. <Form.Item {...formItemLayout} label="公司">
  2. <Select
  3. defaultValue="0"
  4. style={{ width: 120 }}
  5. onChange={(v) => setinputType(v)}
  6. >
  7. <Option value="0">公司名</Option>
  8. <Option value="1">公司ID</Option>
  9. </Select>
  10. {/* 当前方选择框选择公司ID输入时,渲染输入公司ID
  11. 当前方选择框选择公司名输入时,渲染请选择可见公司 */}
  12. {inputType != '0' ? (
  13. <Form.Item
  14. {...formItemLayout}
  15. //此处name需要绑定不同变量名,否则会导致与下方`选择可见公司`选择框变量互相污染
  16. name="company_inputIds"
  17. noStyle
  18. rules={[{ required: true, message: '输入公司ID' }]}
  19. >
  20. {/* 此处使用antd自带下拉框 */}
  21. <Select
  22. mode="tags"
  23. value={showCompanyIDList}
  24. onChange={(val) => changeCompanyIds(val)}
  25. showArrow={true}
  26. placeholder="输入公司ID"
  27. style={{ minWidth: 250, maxWidth: 350 }}
  28. tokenSeparators={[',']}
  29. />
  30. </Form.Item>
  31. ) : (
  32. //此处调用公用组件
  33. <Form.Item
  34. {...formItemLayout}
  35. name="company_ids"
  36. noStyle
  37. rules={[{ required: true, message: '请选择指定公司' }]}
  38. >
  39. <SuperSelect
  40. value={showCompanyList}
  41. placeholder="请选择可见公司"
  42. loading={companyLoading}
  43. options={companyList}
  44. showArrow={true}
  45. onChange={(val) => {
  46. companyListChange(val);
  47. }}
  48. getData={() => {
  49. getCompanyList();
  50. }}
  51. onSearch={onSearchCompany}
  52. />{' '}
  53. </Form.Item>
  54. )}
  55. </Form.Item>
  56. --------------------------------- 数据处理 ----------------------------------------------------
  57. const params = {
  58. //当 `company_ids`为空时,取`company_inputIds`的值(反之相反),然后将值转为字符串形式(以,隔开)
  59. company_ids:
  60. data?.company_ids?.length > 0
  61. ? data?.company_ids?.map((value) => value.key).join(',')
  62. : !toJS(data?.company_inputIds)
  63. ? undefined
  64. : data?.company_inputIds?.toString(),
  65. };

Ⅵ - 实现From中使用富文本编辑器

  1. 需求场景:当你的表单提交中有富文本编辑器,且你要将其变为受控组件时
  2. 难点分析:
  • 如何将让from认到富文本编辑器中的值:使用form.setFieldsValue方法设置Form.Item绑定的默认值,用作校验
  • 为什么不用setState去将其绑定成受控组件?—>你不应该用 setState,可以使用 form.setFieldsValue 来动态改变表单值
    —> (此处为官方文档原话,点我传送)
  1. 代码及其注解
  1. 富文本编辑器官网 —>点我跳转
  1. ----------------------- 组件调用处 ------------------------
  2. <Form.Item
  3. {...formItemLayout}
  4. name="EditorContent"
  5. style={{ width: '120%' }}
  6. rules={[
  7. {
  8. required: true,
  9. validator: (_, value) => {
  10. //此处只是简单判断是否为空,
  11. //但其实value在store中将undefined的值赋值成了'<p><br/></p>';
  12. //如果要严格判断是否为空,应加正则进行判断
  13. if (value) return Promise.resolve();
  14. return Promise.reject('请输入推送内容');
  15. },
  16. },
  17. ]}
  18. >
  19. {/* 富文本编辑器-- 此组件为封装的组件*/}
  20. <SuperWangeditor
  21. EditorContent={newEditorContent}
  22. setEditorContent={setEditorContent}
  23. setContentType={setContentType}
  24. disable={true}
  25. //此处将`changeHandle`方法传给子组件,目的是让其将值传递出来给`form.setFieldsValue`使用
  26. changeHandle={(content) => {
  27. form.setFieldsValue({
  28. 'EditorContent': content,
  29. });
  30. }}
  31. />
  32. </Form.Item>
  33. ------------------------ 封装的富文本组件中的`onchange`事件处代码 ----------------------------------------
  34. import Wangeditor from 'wangeditor';
  35. ..省略..
  36. componentDidMount() {
  37. const { changeHandle } = this.props;
  38. //当输入修改时触发
  39. //3.x版本写法
  40. // editor.customConfig.onchange = (html) => {
  41. // //将子组件的值抛给父类,这样可以使得此组件更有通用性 ----------------->主要是这步
  42. // if (changeHandle) changeHandle?.(html);
  43. // //文本
  44. // if (setEditorContent || setContentType) {
  45. // //设置内容
  46. // setEditorContent(editor.txt.html());
  47. // setContentType(false);
  48. // }
  49. // };
  50. //4.x版本应将`customConfig`更改为config
  51. editor.config.onchange = (html) => {
  52. // console.log(html)
  53. //将子组件的值抛给父类,这样可以使得此组件更有通用性
  54. if (changeHandle) changeHandle?.(html);
  55. //文本
  56. // console.log(editor.txt.text())
  57. if (setEditorContent || setContentType) {
  58. //设置内容
  59. setEditorContent(editor.txt.html());
  60. setContentType(false);
  61. }
  62. };
  63. }
  64. ---------------------- 对于输入富文本数据进行处理(此处可忽略,只是指出数据处理) --------------------------------------
  65. @computed
  66. get newEditorContent() {
  67. let content;
  68. //此处如果为undefined时置换成'<p><br/></p>' -->所以在上述校验条件中指出:如果严格校验输入为空以及纯空格需要用正则判断
  69. if (typeof this.tableData.content == 'undefined') {
  70. content = '<p><br/></p>';
  71. } else {
  72. content = toJS(this.tableData?.content);
  73. }
  74. return content;
  75. }

Ⅶ - 给表单中输入框(其他如选择框)等赋初始值

此处拿 inputNumber 作为例子

a) 我们的错误做法

我们从官方文档中可以知道,设置默认值有一个专门的API: defaultValue —> 初次渲染时会进行赋初始值,且只会执行一次,但是在某些场景下,却发现 defaultValue 并不能完成我们预期的初始化操作,此处举一例本人开发中遇到的场景:

当我们需要写一个 inputNumber 同时设置其 最大值(max)、最小值(min)、初始值(defaultValue) ,通常我们是这样做的

  • 这三个值绑定的都是可改变的state
  • 在页面加载初始化函数中调用接口从而获取这三个值
  • 获取到值后state改变,重新渲染页面,将这三个值渲染到页面上

b) 这时候问题来了:

  • 首先一种情况:你会发现你使用 inputNumber 给的初始值并不是绑定的state的最新值,更像是初始化定义时的值(定义state时没给初始值就是undefined)
  • 另一种情况:也就是在 inputNumber 中出现的 —> 输入框的默认值会是最小值 or 最大值

c) 问题

① 为何设置的默认值不是最新的state

当你 初始值(defaultValue) 绑定的值需要从异步接口中获取那么实际上我们页面不会等到请求结束才渲染,而是先渲染页面(此时就运行了 defaultValue)这个API了),等到接口返回将state修改了再重新渲染绑定这些state部分的页面元素 那么即使后面接口获得数据改变了这个值,页面也只会渲染刚开始的值

② 为何 inputNumber 默认值会成为最大值 or 最小值

其实在上面的问题解析中就知道了, 初始值(defaultValue) 只会渲染一次,不论你一开始 state 给定的值是0(防止错误)、正常的值甚至是直接不给初始化(就默认为undefined),实际上他都是只有初次渲染时生效,你可以理解为实际上页面可能进行了不止一次渲染

  • 第一次渲染: 此时页面不管你state是否还要改变,就当前给定的 最大值(max)、最小值(min)、初始值(defaultValue) 渲染到页面上,此时 初始值(defaultValue) 是生效的
  • 再渲染:当 最大值(max)、最小值(min)、初始值(defaultValue) 绑定的state发生改变时(实际上就是请求的接口数据返回了),初始值(defaultValue)因为再第一次渲染中已经调用过一次,所以无法再给这个 inputNumber 设置初始值了,这时如果你第一次的 初始值 超出当前最大值、最小值范围时,就会被最大值最小值限制

d) 解决方案

实际上有很多解决方案,这里列举一两个

  • 定义一个 state,但不再使用 defaultValue 方法,而是直接将 value绑定state,初始化给默认值也直接修改state即可
  • 如果你的输入框在 From 表单中 ,那么你可以在初始化生命周期(或useEffect) 中 调用 from.setFieldsValue({…}),相当于在每次重绘时都进行一次初始值写入

2、Select 选择器

Ⅰ - filterOption 筛选下拉项自定义筛选条件

filterOption :是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false

注意:要配合 showSearch 一起使用,首先要支持搜索 然后用

a) 使用场景

一般常见场景来说,我们可以只通过 showSearch为true 的方式做到输入内容关联下拉项,但是某些场景就需要配合 filterOption使用了

  • 当我们进行搜索的内容不是 Option 项中绑定的 value, 而是它的 children 值呢? 比如你value绑定的是订单id 而 children 则是显示时展示的 订单名称
  • 那么这时候单单使用 showSearch 就不足以完成我们的需求了:我们输入订单名称去关联搜索下面下拉项订单名称

b) 使用示例

AntDesign_ofReact使用笔记 - 图3

  1. <Select
  2. placeholder="请输入或下拉选择IP名称"
  3. showSearch
  4. //动态搜索Option的值 而不是value中的值
  5. //正则:当 inputValue 包含于 option 时返回true
  6. filterOption={(inputValue, option) => new RegExp(inputValue).test(option.children)}
  7. >>>
  8. {nameList?.map(item => (//下拉项value绑定id 展示却展示名称
  9. <Option key={item?.id} value={item?.id}>
  10. {item?.proxy_name}
  11. </Option>
  12. ))}
  13. </Select>

Ⅱ - 自定义添加下拉项

效果展示

AntDesign_ofReact使用笔记 - 图4

  1. const [form] = Form.useForm();
  2. const [initsPlatforms, setInitsPlatforms] = useState([]); //总的下拉列表
  3. const [newPlatforms, setNewPlatforms] = useState(''); //新增内容输入框绑定数据
  4. //自定义平台输入框数据绑定
  5. const onChangeName = (event) => {
  6. if (event?.target?.value?.trim()?.length != 0) setNewPlatforms(event.target.value);
  7. else setNewPlatforms(undefined);
  8. };
  9. //自定义平台的添加操作
  10. const addItem = (type) => {
  11. //如果为空字符串或者为undefined 则直接中断
  12. if (!newPlatforms || newPlatforms.trim().length == 0) return;
  13. //将添加标签输入框的内容加入 下拉列表中
  14. setInitsPlatforms([...initsPlatforms, newPlatforms]);
  15. //本人用的from提交,这行代码是将自定义平台直接加到选中框中
  16. form.setFieldsValue({
  17. [type]: [...form.getFieldValue(type), newPlatforms],
  18. });
  19. setNewPlatforms('');
  20. };
  21. /********************* RreatNode ***********************************/
  22. <Form.Item label="常见可用平台" name="yes_platforms">
  23. <Select
  24. placeholder="请输入或下拉选择IP名称"
  25. showSearch
  26. mode="multiple"
  27. //动态搜索Option的值 而不是value中的值
  28. //正则:当 inputValue 包含于 option 时返回true
  29. filterOption={(inputValue, option) => new RegExp(inputValue).test(option.children)}
  30. dropdownRender={(menu) => (
  31. <div>
  32. {menu}
  33. <Divider style={{ margin: '4px 0' }} />
  34. <div style={{ display: 'flex', flexWrap: 'nowrap', padding: 8 }}>
  35. <Input style={{ flex: 'auto' }} value={newPlatforms} onChange={onChangeName} />
  36. <a
  37. style={{ flex: 'none', padding: '8px', display: 'block', cursor: 'pointer' }}
  38. onClick={() => addItem('yes_platforms')}
  39. >
  40. <PlusOutlined /> 添加自定义平台
  41. </a>
  42. </div>
  43. </div>
  44. )}
  45. >
  46. {initsPlatforms?.map((
  47. item //下拉项value绑定id 展示却展示名称
  48. ) => (
  49. <Option key={item} value={item}>
  50. {item}
  51. </Option>
  52. ))}
  53. </Select>
  54. </Form.Item>

二、数据展示

1、Table表格

基本前端大部分页面数据展示都是使用Table进行展示

Ⅰ-列表渲染映射文字

  1. 场景:当你对下列表渲染时,服务端传送过来的值是数字(0,1,2),而你要显示成相对应的文字时
  2. 代码示例1:
  1. 代码示例2,写法不同效果相同,下面是本人喜欢的写法:
  1. <Table>
  2. <Column
  3. title="状态"
  4. dataIndex="status"
  5. render={(data) => {
  6. const text = {
  7. 0: '已绑定',
  8. 1: '未绑定',
  9. 2: '已删除',
  10. };
  11. return text[data];
  12. }}
  13. />
  14. </Table>
  1. /** 数据字典 company-const.ts **/
  2. const SHOPSTATUSDICT = {
  3. 0: '已删除',
  4. 1: '正常',
  5. 2: '未绑定IP',
  6. };
  7. export{ SHOPSTATUSDICT }
  8. /** 页面调用出 */
  9. import { SHOPSTATUSDICT } from '../common/company-const'//导入数据字典
  10. const columns = [ {
  11. title: '状态',
  12. dataIndex: 'status',
  13. ellipsis: true,
  14. render: text=>SHOPSTATUSDICT[text]//进行状态数据映射
  15. },]
  16. return (
  17. <Fragment>
  18. <Table columns={columns} />
  19. </Fragment>
  20. );

Ⅱ-列表渲染映射-小数转百分比

  1. 当服务端给你的数据是小数,而你需要将其渲染成百分比进行展示 0.25—>25%
  2. 解析:应用的是render相关知识点
  3. 代码示例:
  4. 转换函数代码
  5. 列表table组件代码
  6. 如果对于if(!!!point)此行代码不懂的同学可以看本人在js笔记中的[js中为什么需要!!?](https://gitee.com/hongjilin/hongs-study-notes/blob/master/%E7%BC%96%E7%A8%8B_%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/(html+css+js)%E9%9B%B6%E6%95%A3%E7%AC%94%E8%AE%B0,%E5%BE%85%E6%A2%B3%E7%90%86/JavaScript%E7%AC%94%E8%AE%B0(%E9%9B%B6%E6%95%A3%E5%BE%85%E6%A2%B3%E7%90%86)/js%E4%B8%AD%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81!!%EF%BC%9F.md)部分
  1. /**
  2. * 将小数转化为百分比
  3. * @param point
  4. * @returns
  5. */
  6. toPercent=(point:number)=>{
  7. //判断是否为空,如果为空不做处理 -->此处如果为空要转换成0,将此行代码下移一位即可
  8. if(!!!point) return point
  9. //服务端可能传来的数据是字符串,转换一下
  10. point=Number(point)
  11. if (point==0) return 0;
  12. let str=Number(point*100).toFixed()+"%";
  13. return str;
  14. }
  1. //写法一
  2. <Table>
  3. <Column title="抽成比例" dataIndex="rate"
  4. //将小数转换成百分比,当为数字时,进行转换
  5. render={(data) => (typeof data =='number')? tool.toPercent(data):data }
  6. />
  7. </Table>
  8. //写法二
  9. const columns = [ {
  10. title: '抽成比例',
  11. dataIndex: 'rate',
  12. width: 150,
  13. ellipsis: true,
  14. //将小数转换成百分比
  15. render: data => tool.toPercent(data)
  16. },];
  17. <Table columns={columns}></Table>

Ⅲ-表格列固定

  1. 需求场景:当你的列表过长时,使用滚轮进行拖动会导致用户体验感较差,这时就需要进行表格列固定
  2. 未使用时效果 AntDesign_ofReact使用笔记 - 图5

    1. 使用后效果

    AntDesign_ofReact使用笔记 - 图6
    ps :截图中展示的都是开发中的测试假数据

  3. 代码示例:只给出必要部分

    1. css样式代码(需要给定width,否则无法生效,给定高度,防止超出)
    2. js调用代码示例1
    3. js调用2:(都可实现,效果一样)
  1. 注意:需要给定宽度,不然不会生效
  1. .tableWidth{
  2. width: 1600px;
  3. height: calc(100% - 48px);
  4. :global {
  5. .ant-table-wrapper,
  6. .ant-spin-nested-loading,
  7. .ant-spin-container,
  8. .ant-table-container {
  9. height: 100%;
  10. }
  11. .ant-table {
  12. height: calc(100% - 48px);
  13. }
  14. .ant-table-pagination.ant-pagination,
  15. div.ant-typography,
  16. .ant-typography p {
  17. margin-bottom: 0;
  18. }
  19. }
  20. }
  1. const columns = [
  2. {
  3. title: '公司ID',
  4. fixed: 'left', //这就是固定在左边写法
  5. dataIndex: 'companyId',
  6. width: 150,
  7. ellipsis: true,
  8. },
  9. ]
  10. return (
  11. <Table
  12. className={` ${style.tableWidth}`}
  13. columns={columns}
  14. scroll={{ x: 600 }}
  15. />
  16. );
  1. const columns = [
  2. {
  3. title: '名称',
  4. dataIndex: 'name',
  5. width: 150,
  6. fixed: 'left' as const,
  7. }, {
  8. title: '操作',
  9. dataIndex: 'agentId',
  10. width: 400,
  11. fixed: 'right' as const,
  12. }
  13. ]
  14. return (
  15. <div className={style.tableWidth}>
  16. <Table
  17. scroll={{ x: 600, y: 'calc(100% - 48px)' }}
  18. columns={columns}
  19. />
  20. </div>
  21. );

Ⅳ-列表内容超出隐藏且悬停显示全

这属于超长连续字段(长数字和长单词)破坏表格布局的问题(即使你指定了列的宽度也会被挤开),组件之前默认内加过word-break: break-word;去纠正此类布局,又会引起#13624的问题—列高也会被撑开(此处给的例子于其不一样,但原理相似)

  1. 需求场景:当我的列表内容过多使得表格撑开,导致整个表格样式与希望效果不符合时,我希望能将其超出隐藏,并能悬停显示全部信息

    AntDesign_ofReact使用笔记 - 图7

  2. 代码实现
  1. 效果实现图

    AntDesign_ofReact使用笔记 - 图8

  1. import { Tooltip } from 'antd';
  2. const columns=[
  3. { title: '渠道商账号', dataIndex: 'username',
  4. width: 150,
  5. onCell: () => {
  6. return {
  7. style: {
  8. maxWidth: 180,
  9. overflow: 'hidden',
  10. whiteSpace: 'nowrap',
  11. textOverflow:'ellipsis',
  12. cursor:'pointer'
  13. }
  14. }
  15. },
  16. //此处引入用作悬停显示全
  17. render: (text) => <Tooltip placement="topLeft" title={text}>{text}</Tooltip>
  18. },
  19. ]

Ⅴ-Table表中使用气泡提示Tooltip

AntD的Table表头title加Icon图标和气泡提示Tooltip

  1. 需求场景:当你的产品要你实现这个效果时

AntDesign_ofReact使用笔记 - 图9

  1. 代码实现:直接在title中写即可
  1. 效果展示

AntDesign_ofReact使用笔记 - 图10

  1. import React, { Component } from 'react';
  2. import { Table, Button, Modal, Typography } from 'antd';
  3. import { QuestionCircleOutlined } from '@ant-design/icons';
  4. import { Tooltip } from 'antd';
  5. interface IProps {
  6. store: Store;
  7. }
  8. const ManageTable = (props: IProps) => {
  9. const { store } = props;
  10. const columns = [
  11. {
  12. dataIndex: 'monthCount',
  13. ellipsis: true,
  14. //效果实现就在这行
  15. title:
  16. <div> 本月新增付费IP数&nbsp;
  17. <Tooltip placement='top' title='仅为当前月新增付费IP数'>
  18. <QuestionCircleOutlined />
  19. </Tooltip>
  20. </div>,
  21. },
  22. ];
  23. return (
  24. <Table
  25. rowKey={(record, index) => record.id || index}
  26. className="table-box"
  27. columns={columns}
  28. />
  29. );
  30. };
  31. export default observer(ManageTable);

列表中正常使用气泡提示Tooltip

  1. 正常列表中使用气泡提示
  2. 代码示例:—-在columns的render中使用
  1. 实现效果

AntDesign_ofReact使用笔记 - 图11

  1. const columns = [ {
  2. title: '列名',
  3. dataIndex: '属性名',
  4. render: (text, record) => (
  5. <Tooltip placement="top" title={text}>
  6. <a onClick={() => showModal(true, record.id, text)}>{text}</a>
  7. </Tooltip>
  8. ),
  9. },
  10. ]

列表中使用[Tooltip]组件却出现两个提示的问题解决

  1. 问题场景:当你想为表格中超出隐藏文字部分加气泡提示时却发现出现两个提示
  • 问题代码:
  • 问题截图与分析:
    AntDesign_ofReact使用笔记 - 图12 .
  1. 问题分析:
  • render()中返回如果是纯文本,会被[Table]自动渲染成白色气泡提示,但此提示不符合我们自己的需求(无法复制、不够美观)
  • 所以我们返回给render()的可以是自己定义的DOM.但是此处也会引出一个新的问题,看下方—>
    • 初次改进代码:
    • 初次改进效果:
      AntDesign_ofReact使用笔记 - 图13.
  • 可以看出虽然解决了双气泡提示的问题,但也引出了一个新问题::返回的新的DOM它不受前方ellipsis属性影响,虽然气泡提示成功变为只有一个,但是下方文本仍然超出,怎么办?
  1. 最正确写法(数组写法也一样,自行转换下即可):
  • 代码
  • 效果截图:
    AntDesign_ofReact使用笔记 - 图14

于此问题完美解决了

  1. <Column
  2. title="支付宝账户"
  3. dataIndex="zfb_account_name"
  4. ellipsis
  5. width={120}
  6. render={text => (
  7. <Tooltip placement="top" title={text}>
  8. {/* {text} //此处直接将内容数据返回出去渲染 */}
  9. {`这是返回出去列表渲染的:${text}`}
  10. </Tooltip>
  11. )}
  12. />
  1. -----------------------修改后出现问题的代码------------------------------------;
  2. <Column
  3. title="支付宝账户"
  4. dataIndex="zfb_account_name"
  5. ellipsis
  6. width={120}
  7. render={text => (
  8. <Tooltip placement="top" title={text}>
  9. {/* {text} //此处直接将内容数据返回出去渲染 */}
  10. <div>{`这是返回出去列表渲染的:${text}`}</div>
  11. </Tooltip>
  12. )}
  13. />
  1. ----------------------- 正确写法1:给dom加以下样式 -----------------------------------;
  2. //tsx
  3. <Column
  4. title="支付宝账户"
  5. dataIndex="zfb_account_name"
  6. // ellipsis 此属性无法影响到render返回出来的dom节点,无用了,去除
  7. width={120}
  8. render={text => (
  9. <Tooltip placement="top" title={text}>
  10. {/* {text} //此处直接将内容数据返回出去渲染 */}
  11. <div className={style.text}>{`这是返回出去列表渲染的:${text}`}</div>
  12. </Tooltip>
  13. )}
  14. />
  15. //scss
  16. .text {
  17. white-space: nowrap;
  18. overflow: hidden;
  19. text-overflow: ellipsis;
  20. }
  21. ----------------------- 正确写法2:直接将写成内联样式(不推荐) -----------------------------------;
  22. <Column
  23. title="支付宝账户"
  24. dataIndex="zfb_account_name"
  25. // ellipsis 此属性无法影响到render返回出来的dom节点,无用了,去除
  26. width={120}
  27. render={text => (
  28. <Tooltip placement="top" title={text}>
  29. <div style={{
  30. overflow: 'hidden',
  31. whiteSpace: 'nowrap',
  32. textOverflow: 'ellipsis',
  33. }}>{text}</div>
  34. </Tooltip>
  35. )}
  36. />

Ⅵ-table排序对比大小相关

antd列表排序第一次点击逆序第二次正序第三次是恢复到默认,依次循环.所以每第三次点击并不是无效,而是本身需要此效果

其实可以直接写,只是如果不抽出,多处使用重复的代码,万一修改就很麻烦

_table按时间排序_

  1. 需求场景分析:当你需要对列表中数据按照时间排序,但是antd默认排序方法无法认出根据你传入对象的何属性进行排序,此时你就需要自己写时间排序
  2. 代码实现与截图

AntDesign_ofReact使用笔记 - 图15

  1. //此处贴士:antd第一次点击逆序第二次正序第三次是回复到默认,依次循环
  2. {
  3. title: '采集结束时间',
  4. dataIndex: 'end_time',
  5. key: 'end_time',
  6. sorter: (a, b) => new Date(a.end_time).getTime() - new Date(b.end_time).getTime()
  7. },
  8. -----------------封装与调用--------------------------
  9. 工具函数抽出:
  10. /**
  11. * 时间列表排序方法
  12. * 可以更换a,b顺序,做到初次为逆序还是正序排序
  13. * @param a 包含时间属性的对象a
  14. * @param b 包含时间属性的对象b
  15. * @param type 作为排序依据的时间属性名字
  16. * @returns number 利用正负数进行判断
  17. */
  18. timeSorter = (a:object, b:object):Function => (type):number => new Date(a[type]).getTime() - new Date(b[type]).getTime()
  19. //此处b-a(看自己需求)原因为要符合服务端给定的数据,服务端给的数据默认越以前的时间在前面,防止第一次看上去无效
  20. 调用: sorter: (a, b) => tool.timeSorter(b, a)('start_time')

_table通用对比大小_

  1. 包括时间排序,你都能使用此封装函数
  2. 代码实现与截图

AntDesign_ofReact使用笔记 - 图16

注意:排序返回应为正负数[如1、-1]而不是boolean类型

  1. -----------------封装与调用--------------------------
  2. 工具函数抽出:
  3. /**
  4. * 通用对比法
  5. * @param a 包含要对比属性的对象a
  6. * @param b 包含要对比属性的对象b
  7. * @param type 作为排序依据的属性名字
  8. * @returns boolean
  9. */
  10. //commonSorter = (a:object, b:object):Function=> (type):boolean => a[type] > b[type] -->错误,返回应为1或者-1
  11. commonSorter = (a:object, b:object):Function=> (type):number => a[type] > b[type] ? 1 : -1
  12. sorter={(a: object, b: object) => tool.commonSorter(a, b)('url')}

Ⅶ - 以其他列作为本列展示筛选条件

  1. 举个实际场景:
  • 当我需要根据 [is_dynamic] 字段判断 本列展示的是 [IP名称] 还是 [IP地址] 时
  1. api概述: 列的 render() 方法自动接受两个参数
  • 第一个参数: daraIndex 中绑定字段的值
  • 第二个参数: 本行数据所有属性名与值
  1. 代码实现与截图
  • 实现方法1:row含有本行所有字段
  • 实现方法2:其实就是换个写法

AntDesign_ofReact使用笔记 - 图17

AntDesign_ofReact使用笔记 - 图18

2、Tree 树形控件

官方文档部分

ps:下方解决代码只给出本效果所需必要代码,其余代码不展示出来—>必须代码上都有相应注释

Ⅰ- 实现点击复选框后的文字也能进行选择的效果

  1. 需求场景:

AntDesign_ofReact使用笔记 - 图19

  1. API概述:
  • [checkedKeys]API是显示记录表单中选中的节点
  • [onCheck]API是针对前面的复选框点击,点击时传参数为所有选中的数组,此处可以直接看官方文档就能实现
  • [onSelect]API是针对后面文字树节点的点击,但是点击时传参数为当前选中树节点,且其选中与未选中与[checkedKeys]无关联
  1. 思路分析:
  • 首先,声明[checkedKeys]变量,然后从服务端获取已有选中项,进行初始化
  • 不论是[onCheck]还是[onSelect],都是对于checkedKeys变量进行拼装操作,再写入渲染
  • 只是说[onSelect]传来的参数需要经过加工,略显复杂,详情请看下方代码
  1. 代码:
  1. 效果展示:

AntDesign_ofReact使用笔记 - 图20

  1. import { Button, Form, Input, Tree } from 'antd';
  2. import { inject, observer, useLocalStore } from 'mobx-react';
  3. import React, { useEffect, useMemo, useRef, useState } from 'react';
  4. import style from './style.scss';
  5. const EditModal = (props) => {
  6. //用来存 [checkedKeys]-->已经选中的状态 通常需要从服务端先获取初始化原先已经选中的数据
  7. const [checkedKeys, setCheckedKeys] = useState([]);
  8. const [form] = Form.useForm();
  9. /**
  10. * 一 复选框选中函数
  11. * @param checked 传入当前勾选上的所有节点key
  12. */
  13. const handleSearchTreeNode = (checked) => {
  14. setCheckedKeys(checked);
  15. };
  16. /**
  17. * 二 树节点选中函数
  18. * @param checked 选中时传入当前树节点 --注意:当为未选中状态时传入为空,所以不能用作[权限选中判断]
  19. * @param e 点击树节点时传入整个树节点数据信息 --不论是否选中都会传入
  20. * @param node
  21. * @param event
  22. */
  23. const handleSelectTreeNode = (checked, e, node, event) => {
  24. //将点击的树节点的[key]解构出来
  25. const {
  26. node: { key },
  27. } = e;
  28. //声明一个SET数组,将key存入(以防万一同时防止重复赋值)
  29. const data = Array.from(new Set([...checkedKeys, key]));
  30. //首先判断原有[树数组:checkedKeys]中是否含有当前点击的[key],如果有则筛选掉,
  31. if (checkedKeys.includes(key))
  32. setCheckedKeys(checkedKeys.filter((value) => value != key));
  33. //如果原有[树数组]中不含有,则直接将新增好的[data]写入替代掉[树数组:checkedKeys]
  34. else setCheckedKeys(data);
  35. };
  36. return (
  37. <Form onFinish={submit} {...formItemLayout} form={form}>
  38. <Form.Item label="权限" required>
  39. <Form.Item
  40. name="roles"
  41. noStyle
  42. rules={[
  43. () => ({
  44. validator(rule: any, value: any) {
  45. if (checkedKeys && checkedKeys.length === 0) return Promise.reject('请选择角色对应的权限');
  46. return Promise.resolve();
  47. },
  48. }),
  49. ]}
  50. >
  51. <Tree
  52. defaultCheckedKeys={[]}
  53. checkable
  54. expandedKeys={expandedKeys}
  55. onExpand={(keys) => {
  56. setExpandedKeys(keys);
  57. }}
  58. //此处绑定所有Tree数据
  59. treeData={menuTree}
  60. //此处绑定选中的key
  61. checkedKeys={checkedKeys}
  62. //此处为复选框点击触发API
  63. onCheck={handleSearchTreeNode}
  64. //此处为后面的文字树节点点击触发API
  65. onSelect={handleSelectTreeNode}
  66. height={300}
  67. />
  68. </Form.Item>
  69. </Form.Item>
  70. </div>
  71. </Form>
  72. );
  73. };

3、Tooltip文字提示

Ⅰ - 自定义悬停提示

一般我们的悬停提示就是直接将数据赋值到 [title] 上,但是目前遇到一个需求,是要求悬停提示需要换行、指定行带颜色

实际上 [ title ] 可以接受参数是一个ReactNode 即直接一个节点

效果展示

AntDesign_ofReact使用笔记 - 图21

  1. <Tooltip title={this.remarksNode(remarks, remarks_v5, yes_platforms, no_platforms)}>
  2. <p className={style.remarks}>{data}</p>
  3. </Tooltip>
  4. // 生成ReactNode 函数
  5. const remarksNode = (remarks, remarks_v5, yes_platforms, no_platforms) => {
  6. return (
  7. <div className={style.zz}>
  8. <span>3版本提示语:</span>
  9. <span>{remarks}</span>
  10. <span> 5版本提示语:</span>
  11. <span> {remarks_v5}</span>
  12. <span>常见可用平台: {yes_platforms?.toString()}</span>
  13. <span style={{color:'red'}}>不推荐使用平台: {no_platforms?.toString()}</span>
  14. </div>
  15. );
  16. };

image-20210519174400852.pngimage-20210519180215667.pngimage-20210519180836289.pngimage-20210520160244113.pngimage-20210520161131163.pngimage-20210617185457284.pngimage-20210617185606230.pngimage-20210630115858466.pngimage-20210705164549793.pngimage-20210706124542682.pngimage-20210708114340551.pngimage-20210712161809111.pngimage-20210712162540686.pngimage-20210712163609695.pngimage-20210714140338803.pngimage-20210715153029004.pngimage-20210916142227728.pngimage-20210928105404801.pngimage-20210928120121096.pngTree选中效果.gif列表筛选条件2.png列表筛选条件3.png