antd4.x开发过程中的一些坑

一: 表单验证:

相较vue中表单验证,antd中对输入框的验证全部放到了Form.Item中。同时触发的事件诸如onBlur,onChangeForm.Item中,(通过validateTrigger来指定)

2 对于自定义校验validator函数。它会在每次事件触发的时候执行,这样就会出现如果设置了

rules={
                        [
                            {   required: true,
                                message: '手机号不能为空'
                            },
                            
                            {
                                required: true,
                                validator:(rule, value) => {
                                    if(value){
                                        let reg=/^1(3|4|5|6|7|8|9)\d{9}$/g;
                                        if(reg.test(value)) {
                                            return Promise.resolve()
                                        }else{
                                            return Promise.reject('手机号格式错误')
                                        }
                                    }else{
                                        return Promise.reject('请输入正确的手机号')
                                    }
                                  }
                            }
                        ]
                    }   

两个验证规则。原本的目的是在没有输入任何值时只提示“手机号不能为空”,结果同时出现“请输入正确的手机号”“手机号格式错误”两个报错。也就是validator优先级最高。所以解决办法有两种:

(1)所有的验证放在valiator中包括为空的情况

(2)不要valiator函数,而是把为空和验证规则拆开,如下:


                <Form.Item
                    name="account"
                    validateTrigger="onBlur"
                    rules={
                        [
                            {   required: true,
                                message: '手机号不能为空'
                            },
                            {
                                 pattern:/^1(3|4|5|6|7|8|9)\d{9}$/g,
                                 message:"请输入正确的手机号"
                             },
                            
                        ]
                    }     
                >
                    <Input  size="large" max={11} value={account} allowClear  prefix={<IconFont type="icon-zhanghao"  />}/>
                </Form.Item>

有时候我们表单提交不一定是在表单的submit按钮下。可能是在其他区域点击触发表单的整体验证。可以通过 两种方式来实现:

(1) 直接通过useForm获取form的引用

import {Modal,Form, } from 'antd';

const [form] = Form.useForm()

function ComName(){

 
    cosnt validata=()=>{
             form.setFieldsValue({
                catagoryName:data.name,
                 
        }) 
    }
return(
    <div>
             <Form 
                    labelCol={{ span: 6 }}
                    wrapperCol={{ span: 18 }}
                    form={form} 
                    initialValues={formInitialValues}
            >
                   <Form.Item 
                        label="类目名"
                        name="catagoryName" 
                        validateTrigger='onBlur'  
                        required
                        
                            ]}>
                        <Input  style={{ width: 320 }} value={catagoryName} />
                    </Form.Item>>
            </Form>
            <Button onClick={validata}>提交</Button>
    </div>
)

}

  方式二。通过useRef获取form的引用

import { useRef, useEffect} from 'react';

function EditCatagory(props){
    
    const fromRef=useRef()

    const submit=()=>{
            fromRef.current.validateFields().then(res=>{

            }).catch(_=>{

            })


    }

    return (
            <div>
              <Form 
                    labelCol={{ span: 6 }}
                    wrapperCol={{ span: 18 }}
                    form={form} 
                    ref={fromRef}
                    initialValues={formInitialValues}
                >
                    xxx...
               </Form>
                <Button onClick={submit}>提交</Button>
            </div>
    )

}

表单的自定义验证的两种方式:

(1) rules里直接通过数组配置规则,如下:

 <Form.Item
                    name="account"
                    validateTrigger="onBlur"
                    rules={
                        [
                            {   required: true,
                                message: '手机号不能为空'
                            },
                            {
                                 pattern:/^1(3|4|5|6|7|8|9)\d{9}$/g,
                                 message:"请输入正确的手机号"
                             },
                            
                        ]
                    }     
                >
                    <Input  size="large" max={11} value={account} allowClear  prefix={<IconFont type="icon-zhanghao"  />}/>
                </Form.Item>

(2) 自定义验证函数validator,注意返回的是一个promise.resove或者reject以后的值:验证通过直接通过promise.resolve()值出来。验证不通过则需要通过promise.reject()抛出错误原因

  const validatorCatagory=(rule, value,type )=>{
        console.log("value",value)
        console.log("type",type)
        let str=type==="cassify"?"类目":"类目编号"
        if(!value){
            return Promise.reject(`${str}不能为空`)
        }else{
            console.log("value:",value)
            if((/[a-zA-Z0-9]/.test(value))&&(value.length>0&&value.length<=60)){
                setCatagoryNum(value)
                return Promise.resolve(value)
            }else{
                return Promise.reject(`${str}不能含有特殊字符并且不能大于60个字符`)
            }
        }
    }  


<Form.Item 
                        label="类目名"
                        name="type" 
                        validateTrigger='onBlur'  
                        required
                        rules={[
                                {validator: (rule, value,) => validatorCatagory(rule, value,"cassify") },
                            ]}>
                        <Input  style={{ width: 320 }} value={catagoryName} onChange={e=>updataName(e)}/>
                    </Form.Item>

2:设置表单默认值问题:

如下图:

 是否继承属性设置这个选项的默认值根据第一个红色框框的类目位置来决定。它是一个数组。如果数组长度>1,则“否继承属性设置”默认勾选伟“自定义设置”,否则则勾选伟继承上级属性设置“。因为有这层逻辑,所以一开始打算在useEffect里动态设置其defaultValue。开始的代码如下:


function CreateCatagory(props){

    const  attrSettingDialogRef=useRef()
    const [inheritPerporty,setInheritPerporty]=useState(1)
    const [setttingVal,setSetttingVal]=useState(1)
    
    

    const [form] = Form.useForm()
    const formRef = React.createRef();


  
    useEffect(()=>{
       let val= catagoryPositions.length>1?2:1;
       setInheritPerporty(val)
    },[])

    <Form 
                    labelCol={{ span: 6 }}
                    wrapperCol={{ span: 18 }}
                    form={form} 
                    ref={formRef}
                    initialValues={formInitialValues}
                >
                    <Form.Item label="类目名" name="type" rules={[{ required: true, message: '所属类型不能为空' }]}>
                        <Input  style={{ width: 320 }}/>
                    </Form.Item>
                    <Form.Item label="类目编号" name="code" rules={[{ required: true, message: '所属类型不能为空' }]}>
                        <Input  style={{ width: 320 }}/>
                    </Form.Item>
                    <Form.Item label="类目位置" name="position" rules={[{ required: true, message: '属性名不能为空' }]}>
                        <Input  style={{ width: 320 }} disabled defaultValue={catagoryPositions.join("/")}/>
                    </Form.Item>
                    <Form.Item label="是否为末级类目" name="control" rules={[{ required: true, message: '属性控件不能为空' }]}>
                        <Radio.Group onChange={onChange} value={isLastCatagoryVal}>
                            <Radio value={1}>是</Radio>
                            <Radio value={2}>否</Radio>
                        </Radio.Group>
                    </Form.Item>
                    <Form.Item label="是否继承属性设置"  name="inherit"  rules={[{ required: true, message: '属性控件不能为空' }]}>
                        <Radio.Group onChange={inheritPerportyFn} defaulteValue={inheritPerporty} value={setttingVal}>
                            <Radio value={1}>继承上级属性设置</Radio>
                            <Radio value={2}>自定义设置</Radio>
                        </Radio.Group>
                    </Form.Item>
                 </Form>
}

export default CreateCatagory

结果报错:

 顺着报错,initialValues看了下antd的官网有这样一段描述“”

  1. 不再需要也不应该用 onChange 来做数据收集同步(你可以使用 Form 的 onValuesChange),但还是可以继续监听 onChange 事件。

  2. 你不能用控件的 value 或 defaultValue 等属性来设置表单域的值,默认值可以用 Form 里的 initialValues 来设置。注意 initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新。

  3. 你不应该用 setState,可以使用 form.setFieldsValue 来动态改变表单值

所以做了一个尝试:代码改动如下:

import {Modal,Form,Input,Button,Space,Select,Radio,Tabs,Checkbox  } from 'antd';
import { useState ,useRef, useEffect} from 'react';
import "./index.less"
import Iconfont from 'components/iconfont';




const list=[
        {id:"0001",name:"a属性"},
        {id:"0002",name:"b属性"},
        {id:"0003",name:"c属性"},
        {id:"0004",name:"d属性"},
        {id:"0005",name:"e属性"},
        {id:"0006",name:"f属性"},
    ]
    // const catagoryPositions=["一级类目","二级类目"].join("/")
const catagoryPositions=["一级类目","二级类目"]

function CreateCatagory(props){

    const  attrSettingDialogRef=useRef()
    const [isLastCatagoryVal,setIsLastCatagoryVal]=useState(1)
    const [setttingVal,setSetttingVal]=useState(1)
    const [isShowPeroptyRow,setIsShowPeroptyRow]=useState(true)
    
    const formInitialValues=({
        inherit:1
    })

    const [form] = Form.useForm()
    const formRef = React.createRef();


    useEffect(()=>{
       let val= catagoryPositions.length>1?2:1;
       formRef.current.setFieldsValue({
         inherit:val
       })
    },[])


    const onChange=()=>{

    }
    const changeTab=()=>{

    }
    const setAttrValue= ()=>{
        attrSettingDialogRef.current.showModelRef()
        
    }
    const confirmFn=(data)=>{
        console.log("data:",data)
    }
    const inheritPerportyFn=(e)=>{
        console.log("val:",e.target.value)
        e.target.value ===2?setIsShowPeroptyRow(true):setIsShowPeroptyRow(false)
    }
    return (
        <div className="add-attr-page">
            <div className="head-title">
                <Iconfont type="icon-down"></Iconfont>
                基础属性
            </div>
            <div className="basic-info">
                <Form 
                    labelCol={{ span: 6 }}
                    wrapperCol={{ span: 18 }}
                    form={form} 
                    ref={formRef}
                    initialValues={formInitialValues}
                >
                    <Form.Item label="类目名" name="type" rules={[{ required: true, message: '所属类型不能为空' }]}>
                        <Input  style={{ width: 320 }}/>
                    </Form.Item>
                    <Form.Item label="类目编号" name="code" rules={[{ required: true, message: '所属类型不能为空' }]}>
                        <Input  style={{ width: 320 }}/>
                    </Form.Item>
                    <Form.Item label="类目位置" name="position" rules={[{ required: true, message: '属性名不能为空' }]}>
                        <Input  style={{ width: 320 }} disabled defaultValue={catagoryPositions.join("/")}/>
                    </Form.Item>
                    <Form.Item label="是否为末级类目" name="control" rules={[{ required: true, message: '属性控件不能为空' }]}>
                        <Radio.Group onChange={onChange} value={isLastCatagoryVal}>
                            <Radio value={1}>是</Radio>
                            <Radio value={2}>否</Radio>
                        </Radio.Group>
                    </Form.Item>
                    <Form.Item label="是否继承属性设置"  name="inherit"  rules={[{ required: true, message: '属性控件不能为空' }]}>
                        <Radio.Group onChange={inheritPerportyFn}  value={setttingVal}>
                            <Radio value={1}>继承上级属性设置</Radio>
                            <Radio value={2}>自定义设置</Radio>
                        </Radio.Group>
                    </Form.Item>
                 </Form>
            </div> 
                {
                    isShowPeroptyRow?
                    <div className="perptoty-setting-box">
                        <div className="head-title">
                            <Iconfont type="icon-down"></Iconfont> 属性设置
                        </div>
                        <div className="attr-setting">
                            <div className="tab-wrap">
                                <div className='basic-attrs atts-item'>
                                        <div className='name'>定额基础属性:</div>
                                        <div className='attr-setting-container'>
                                            <Space size={20}>
                                            
                                                {                                       
                                                    list.map(item=>(
                                                        <Space size="large">
                                                            <span>
                                                                <Checkbox onChange={onChange}>{item.name}</Checkbox>
                                                                <Iconfont type="icon-edit" onClick={setAttrValue}></Iconfont>
                                                            </span>
                                                            <span>
                                                                <Checkbox onChange={onChange}>必填</Checkbox> 
                                                            </span>
                                                        </Space>
                                                    ))
                                                }
                                            
                                            </Space>
                                        </div>
                                </div>
                                <div className='basic-attrs atts-item'>
                                        <div className='name'>主材属性:</div>
                                        <div className='attr-setting-container'>
                                        <Space>
                                            
                                                {                                       
                                                    list.map(item=>(
                                                        <Space size="large">
                                                            <span>
                                                                <Checkbox onChange={onChange}>{item.name}</Checkbox>
                                                                <Iconfont type="icon-edit" onClick={setAttrValue}></Iconfont>
                                                            </span>
                                                            <span>
                                                                <Checkbox onChange={onChange}>必填</Checkbox> 
                                                            </span>
                                                        </Space>
                                                    ))
                                                }
                                                
                                            </Space>
                                        </div>
                                    </div>
                                    <div className='basic-attrs atts-item'>
                                        <div className='name'>辅材属性:</div>
                                        <div className='attr-setting-container'>
                                        <Space>
                                                
                                                {                                       
                                                    list.map(item=>(
                                                        <Space size="large">
                                                            <span>
                                                                <Checkbox onChange={onChange}>{item.name}</Checkbox>
                                                                <Iconfont type="icon-edit" onClick={setAttrValue}></Iconfont>
                                                            </span>
                                                            <span>
                                                                <Checkbox onChange={onChange}>必填</Checkbox> 
                                                            </span>
                                                        </Space>
                                                    ))
                                                }
                                                
                                            </Space>
                                        </div>
                                    </div>
                            </div>
                            <div className="btns">
                                <Space>
                                    <Button type="">取消</Button>
                                    <Button type="primary">确认</Button>
                                </Space>
                            </div>
                        </div>
                    </div>:""
                }            

        </div>
    )
}

export default CreateCatagory

通过表单本身去进行setFieldsValue操作。把defaultValue的逻辑改为表单的操作。终于可以正常显示。

注意改动的地方:

(1)form表单本身绑定initialValues={formInitialValues} 

(2)定义一个初始值:

  const formInitialValues=({

        inherit:1,

        isLastCatagory:1

    })

(3)

  useEffect(()=>{
       let val= catagoryPositions.length>1?2:1;
       formRef.current.setFieldsValue({
         inherit:val,
         isLastCatagory:val
       })
    },[])

一定要注意这个坑。以下我们再看一个例子。就会发现

 

 这个场景,对vue的双向绑定非常容易。而在react中我最开始是这么实现的。天真的以为类目名称更改的时候,setState类目位置就可以了。最后发现,毫无效果。

 const updataName=(e)=>{
        console.log("e.target.value:",e.target.value)
        setCatagoryName(e.target.value)
        updataCataPos(e.target.value)
    }

    const updataCataPos=(name)=>{
        let _newCataPos=[...catagoryPositions,name];
        let txt=_newCataPos.join("/")
        console.log("tex:",txt)
//注意下面的代码。如果不通过form去操作,单纯靠setCatagoryPositionsTxt(txt)就不会更新
        formRef.current.setFieldsValue({
            catagoryName:name,
            catagoryPositionTxt:txt
          })
   
        setCatagoryPositionsTxt(txt)
   }

这里补充一点:

在antd中,对form的处理有两种思路。一中是通过把表单元素作为受控组件。也就是我们通过形如

<Input value={aaa} onChange={e=>change(e)}>

我们通过给表单元素的value绑定某个值然后通过change事件更改其值。来驱动数据的更改

第二种思路则是最常见的一种:通过form实例的相关方法来驱动:

如下:

import { Form, Input ,Button} from "antd"

const FormDemo = () => {

    const [form] = Form.useForm();

    let initValus = {
        username:"",
        password:""
    }

    const view=()=>{
    //    let res= form.getFieldsValue()
       let res= form.getFieldValue("username")
       console.log("res:",res)
    }

    return (
            <div style={{width:"520px"}}>
                < Form initialValues={initValus} form={form}>
                    <Form.Item name="username" label="用户名">
                        <Input placeholder-="请输入姓名"></Input>
                    </Form.Item>
                    <Form.Item name="password" label="密码">
                        <Input placeholder-="请输入密码"></Input>
                    </Form.Item>
                </Form >
                <Button onClick={view}>查看</Button>
            </div>       
    )
}

export default FormDemo

form实例的getFieldsValue()能获取到每个Form.Item的字段的值;

form实例的getFieldValue(“username”)能获取某个字段,比如usernameForm.Item的字段的值;

form实例的setFieldsValue()能设置某个字段或者所有字段的值。

此二种方法用其一即可、

三 。在表单控件中如何传递参数?

如图:我们想点击勾选的时候,把当前的数据打印出来。

 实现方式:箭头函数传参,注意箭头函数第一个参数只能是e,第二个函数里传对应的数据

 const selectedItem = (e,data) => {
        console.log("e:",e)
        console.log("data:",data)
} 

{
                    list.map(checkboxItem=>(<Checkbox  
                        onChange={(e)=>selectedItem(e,checkboxItem)} 
                        checked={checkboxItem.isChecked}
                    >
                        {checkboxItem.label}
                    </Checkbox>))
}

四。如何取消Modal.confirm的onCancel事件?

业务开发中遇到这么一个需求。点击按钮弹出确认框。点击确认按钮以后需要再出现一个弹窗。暂且叫它弹窗B,当点击弹窗B的关闭按钮时,发现confirm已经不存在了?这个问题很诡异。找了很多办法,终于解决了这个问题:

(方案一:)

在antd的Modal.confirm-api中对onCancel和onOk的描述:

onCancel取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭function(close)-
onOk点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭

也就是说该函数的参数是一个函数。如果我们不让其返回一个promise,就可以阻止它的默认行为。

接下来我们进行改造:

const delCatgory= ()=>{
            Modal.confirm({
                title:"确认删除改属性",
                closable:true,
                width:420,
                okText:"确认",
                cancelText:"取消",
                 onOk:(close)=>{
                     delModalRef.current.showModelRef() //这里通过ref直接操作弹窗B的显示
                 },
                 onCancel:(close)=>{
                     return false
                 }
            })
//注意这里onok和onCancel里传入了close函数。这样就可以再关闭弹窗B的时候让confirm依然存在

(方案二:)通过自定义内容,隐藏页脚的按钮,然后通过自定义内容添加确认和取消两个按钮

   const delCatgory= ()=>{
            Modal.confirm({
                title:"确认删除改属性",
                closable:true,
                width:420,
                okText:"",
                cancelText:"",
                content: <>
                    <p>'执行删除类目,子级类目将同步被删除,确认删除吗?'</p>
                    <div>
                         <Button  onClick={confirmDelAttrModal}>确定</Button>
                         <Button onClick={cancelDelAttrModal}>取消</Button>
                    </div>
                </>,
            })
        }

剩下的就是对Modal.confirm默认的底部按钮通过样式进行了隐藏

五。checkbox.Group通过options传递数据。如何精准的控制单个checkbox的状态?

如下图:勾选checkbox的时候同步显示标签。对应的checkbox同步状态更改

 一开始想到改造原始数据,给每个数据添加一个isChecked状态来控制其选中状态,但是发现在checkbox的change事件里通过e.target.check值和当前值无法同步。后来改变了思路。还是利用checkbox.Group能自动获取到选中的checkbox数组的特征,通过把checkbox变成受控组件来实现。基本实现逻辑如下

import React, { useState, forwardRef, useImperativeHandle,useRef, useEffect } from 'react'
import {Modal,Checkbox,Tag, List } from "antd"
import "./quotaModalStyles/createCatagoryAttrs.less"
import { check } from 'prettier'

const data=[
    {value:'001',label:"把"},
    {value:'002',label:"个"},
    {value:'003',label:"块"},
    {value:'004',label:"打"},
    {value:'005',label:"批"},
]


function Dialog(props, ref) {

  const {confirmFn } = props
  const [visible, setVisible] = useState(false)
  const [list,setList]=useState(data)
  const [checkedList,setCheckedList]=useState([])
  const [arr,setArr]=useState([])



  //lifecycle
  useEffect(()=>{    
    let temp=data.map(item=>({...item,isChecked:false}))
    setList(temp)
  },[])

  //methods--
  // modal的显示与隐藏
  const showModal = () => {
    setVisible(true)
  }
  const hideModal = () => {
    setVisible(false)
  }
  useImperativeHandle(ref, () => ({
    showModelRef: showModal,
    hideModelRef: hideModal
  }))

  const handleClose = () => {
    hideModal();
    let num=100;
    console.log("close")
    confirmFn(num)
    
  }
  const selectedItem = (values) => {
        console.log("values:",values)
        console.log("arr:",arr)
       
        setArr(values)
        console.log("b--:",b)
        let b=[];
        let temp=values
        list.forEach(item=>{
            for(let j=0;j<temp.length;j++){
                if(item.value===temp[j]){
                    b.push(item)
                }
            }
        })
        setCheckedList(b)
  }
  const closeTag=(tag)=>{
    console.log("closeTag-tag-:",tag)
    let tags=checkedList.filter(item=>item.value!==tag.value)
    let res=[];
    tags.forEach(item=>res.push(item.value))
    setArr(res)
    setCheckedList(tags)
  }
  
  return (   
      <Modal
        icon=""
        title="设置属性值"
        width={670}
        footer={null}
        visible={visible}
        centered={true}
        maskClosable={false}
        onCancel={handleClose}
        destroyOnClose={true}
      >
          <div className='create-catagory-attrs-modal'>         
            { <Checkbox.Group
                onChange={selectedItem}
                value={arr}
                options={list}
              >               
             </Checkbox.Group>
            }
            <div className="tag-box">
                {
                    checkedList.map(item=>(
                        <Tag closable onClose={()=>closeTag(item)}>
                            {
                                item.label
                            }
                        </Tag>
                    ))
                }
            </div>
        </div>
      </Modal>
  )
}

export default forwardRef(Dialog)

注意这里我们给checkbox.Group的value赋值给一个数组,所谓受控组件:就是checkbox本身的状态受控于数据arr而不是再根据用户本身是否勾选来控制了。而checkbox.Group的value被绑定到了arr。arr表示被选中的数组列表,这样就意味着哪些数据被勾选了,当前就应该哪些被勾选

六:hooks中对数组push操作useState无效?

场景再现:

 如图。每次点击添加后台类目的时候展示一条数据

原始操作:


  const [types,setTypes]=useState([])

  const addType=()=>{
    
    temp.push(type);
    console.log("temp:",temp)
    setTypes(temp)
}

<Form.Item label="支持后台类目" name="type" rules={[{ required: true, message: '显示位置不能为空' }]}>
            <div>
                {
                    types.map((item,index)=><div key={index}>{item}</div>)
                }
            </div>
            <div>
                <Button size='small' onClick={addType}>+添加后台类目</Button>
            </div>
 </Form.Item>

此时temp打印发现:数组types已经是最新的数据。但是在setTypes这步操作完成以后发现完全没有任何反应。后来经过查阅资料发现。useState对于复杂数据类型的更新条件是两个不同的内存地址,如果是对同一个引用是无效的。所以改成这样:

  const addType=()=>{
        let type=`第${Math.random()*100+10}个类目`
        let temp=JSON.parse(JSON.stringify(types))
        temp.push(type);
        setTypes(temp)
    }

通过深拷贝得到一份新的引用地址。这时候setTypes正常更新

七:antd表格如何实现全选,如何在表格以外去控制表格全选?

 今天碰到这样一个需求:在表格之外通过一个按钮去控制表格的全选。由于对antd组件库不熟悉。导致走了很多弯路:

antd里如何实现基本的全选的?

官方的demo文档里给了一个简单的demo、

const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      
    },
    {
      title: 'Age',
      dataIndex: 'age',
    },
    {
      title: 'Address',
      dataIndex: 'address',
    },
  ];
  
  const data = [];
  for (let i = 0; i < 10; i++) {
    data.push({
      key: i,
      name: `天然气安装 ${i}`,
      code: `00000-${i}`,
       unit: `米`,
       price:2349.00,
       fuliao:2,
       status:`${i}`,
       mark:"xxxxxxxxxxx",
       operate:null
    });
  }
  const rowSelection = {
    onChange: (selectedRowKeys, selectedRows) => {
      if(selectedRowKeys.length===data.length){
        setSelectedRowKeys(selectedRowKeys)
        setIsCheckeAll(true)
      }else{
        setSelectedRowKeys([])
        setIsCheckeAll(false)
      }
    },
    selectedRowKeys,
    getCheckboxProps: (record) => ({
      disabled: record.name === 'Disabled User',
      name: record.name,
    }),
  };

 <Table  
                                       
       hideSelectAll={true}
       rowSelection={rowSelection} 
        columns={columns} 
        dataSource={data}
 >
</Table>

没错。就是这个rowSelection,因为添加了这个属性。所以table头部的复选框能实现选中全部勾选,取消勾选。全部不选中。经过进一步的摸索。发现api里还有这么一句话:

selectedRowKeys指定选中项的 key 数组,需要和 onChange 进行配合

经过尝试发现。它就是解决这个问题的关键。table全选的状态。完全依靠这个数组。这个数组是当前数据的key 的集合。如果勾选了两条数据。那么这个selectedRowKeys的值就是这两条数据的key 的集合。如果勾选了表格所有的行。那么这个selectedRowKeys就说整个data的key的集合。知道了这个关键先生。接下来我们大胆的尝试。给表格外面checkbox的checked绑定一个值。true表示全选(勾选)。此时我们把data的key全部取出来赋值给selectedRowKeys,就能达到目的,

 const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      
    },
    {
      title: 'Age',
      dataIndex: 'age',
    },
    {
      title: 'Address',
      dataIndex: 'address',
    },
  ];
  
  const data = [];
  for (let i = 0; i < 10; i++) {
    data.push({
      key: i,
      name: `天然气安装 ${i}`,
      code: `00000-${i}`,
       unit: `米`,
       price:2349.00,
       fuliao:2,
       status:`${i}`,
       mark:"xxxxxxxxxxx",
       operate:null
    });
  }
function TypeProdPage(){

  const router=useHistory()
  const [isCheckedAll,setCheckAll]=useState(false)
  const [selectedRowKeys,setSelectedRowKeys]=useState([])
  const [isCheckeAll,setIsCheckeAll]=useState(false)

  const onSelect=()=>{

  }
  const onCheck=()=>{
      
  }
  const selectAll=(e)=>{
    if(e.target.checked){
      let keys=[];
      data.forEach(i=>keys.push(i.key))
      setSelectedRowKeys(keys) //这里是关键
    }else{
      setSelectedRowKeys([])
    }
    setIsCheckeAll(e.target.checked)
  }
  const rowSelection = {
    onChange: (selectedRowKeys, selectedRows) => {
      if(selectedRowKeys.length===data.length){
        setSelectedRowKeys(selectedRowKeys)
        setIsCheckeAll(true)  //同步更改表格外面checkbox的状态
      }else{
        setSelectedRowKeys(selectedRowKeys)
        setIsCheckeAll(false)  //同步更改表格外面checkbox的状态
      }
    },
    selectedRowKeys,
    getCheckboxProps: (record) => ({
      disabled: record.name === 'Disabled User',
      name: record.name,
    }),
  };
  const renderTitle=(data)=>{
      console.log("data:",data)
      return <div className="tree-item">
          <div className="tree-txt">{data.title}</div>
          <div className="tree-oper-btn">a</div>
      </div>
  }

    

    return (
        <div className="type-prod-page">
            <Tabs defaultActiveKey="1" size="large">
                {
                    combo.map(item=>
                        ( <TabPane tab={item.name} key={item.id} >
                                <div className="tab-container">
                                    <div className="tree-menu">
                                        <Tree
                                            defaultExpandParent
                                            onSelect={onSelect}
                                            treeData={treeData}
                                            titleRender={
                                                renderTitle
                                            }
                                        />
                                    </div>
                                    <div className="content">
                                    <Table  
                                        title={(data) => 
                                          <div className="table-title">
                                            <Row>
                                                <Col span={12}>
                                                    <Checkbox onChange={(e)=>selectAll(e)} checked={isCheckeAll}>全选</Checkbox>
                                                    已选<span>2</span>个对象,共1200个对象
                                                </Col>
                                                <Col span={12}>
                                                    <Space >
                                                        <Button type="primary">添加定额</Button>
                                                        <Button type="primary">编辑</Button>
                                                        <Button type="primary">移除</Button>
                                                    </Space>
                                                </Col>
                                            </Row>
                                          </div>
                                      }
                                      hideSelectAll={true}
                                      rowSelection={rowSelection} 
                                      columns={columns} 
                                      dataSource={data}
                                    >
                                    </Table>
                                    </div>
                                </div>
                            </TabPane>
                        )
                )
            }
            </Tabs>
        </div>
    )

八:如果手动关闭Modal?

(1)组件外定义一个变量,let modal=null

  (2)  在需要弹窗的定义重新赋值 modal=Modal.confirm({xxxxx})

  (3) 手动关闭通过 modal.destroy()

  let modall=null

 function compentName(){
    
    const del=async()=>{

            console.log("curClickItem----",curClickItem)
            let res=await Service.delCatgory(curClickItem.id)
            console.log("res:",res)
            res.code==0?message.success("删除成功!"):message.error(res.msg)
            modall.destroy() 
    }
    const open=Modal.confirm(
             modall=Modal.confirm({
                title:"确认删除该类目",
                closable:true,
                width:420,
                onOk:del,
                onCancel:()=>{
                     
                }
            })
    )
            

        

        return(
                    <div>
                    
                            <Button onClick={open}>打开</Button>
                    </div>
            )




    }

    九:同一个组件,在创建和编辑这两种场景中如何实现只在编辑时走接口获取信息?

 useEffect(()=>{
    if(props.type=="edit"){
        getAttrDataById(props.id)
    }
    
  },[props.type])

  我们通过props设置一个type,来做区分。同时要注意的是props.type被放到了ueseEffect的依赖中。这样才能实现

十:表格中如何在下拉菜单点击时传递表格行数据?

 如上图。如何实现在点击下拉菜单时获取行数据?

//封装的表格:我们通过传入datasource和column来渲染表格  
const columns = [
    {
      title: '定额名称',
      dataIndex: 'name',

    },
    {
      title: '定额编号',
      dataIndex: 'quotaNum',
      render: (data) => (
        <span >{data}</span>
      )
    },
    {
      title: '定额单位',
      dataIndex: 'unit',
    },
    {
      title: '定额状态',
      dataIndex: 'status',
      render: (data) => (
        data === 1 ? <span>启用</span> : <span>停用</span>
      )
    },
    {
      title: '门店价格',
      dataIndex: 'laborCost',
    },
    {
      title: '销售价格',
      dataIndex: 'laborSale',
    },
    {
      title: '辅料信息',
      dataIndex: 'fuliao',
    },

    {
      title: '主材信息',
      dataIndex: 'mark',
    },
    {
      title: '创建时间',
      dataIndex: 'mark',
    },
    {
      title: '操作',
      dataIndex: 'operate',
      render: (text, data, index) => {
        return (
          <Space>
            <span style={{ cursor: "pointer" }} onClick={viewDetail}>详情</span>
            <span>
              <Dropdown overlay={() => {
                console.log("text", text)
                console.log("data", data)
                return menu(data)
              }} trigger={['click']}>
                <a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
                  ...
                </a>
              </Dropdown>
            </span>
          </Space>
        )
      }
    }
  ];

注意这里我们通过箭头函数的方式返回menu,同时把行数据提过menu传递出去

 const menu = (data) => {
    console.log("++++data:", data)
    return (
      <Menu onClick={(e) => operateDropDownMenu(e, data)}>
        <Menu.Item key="0">
          <span >编辑信息</span>
        </Menu.Item>
        <Menu.Item key="1">
          <span >编辑辅料</span>
        </Menu.Item>
        <Menu.Item key="3">
          <span >编辑主料</span>
        </Menu.Item>
        <Menu.Item key="4">
          <span >编辑门店价格</span>
        </Menu.Item>
      </Menu>
    )
  }

最后在operateDropDownMenu 中得到data,就是行数据

const operateDropDownMenu = (e, data) => {
    let key = e.key

    console.log("data---!!!", data)
    //编辑信息
    if (key == 0) {
      router.push("/quotaManage/shopEdit")
    } else if (key == 1) {
      //编辑辅料
      // 弹窗

    } else if (key == 3) {

      //编辑主料
      // 弹窗

    } else {
      let id = data.id
      // debugger
      EditShopPriceModal({
        title: "编辑门店价格",
        data: {
          id: data.id
        },
        onOk: editShopPriceSuccCb,
        onCancel: () => { }
      })
    }
  }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在React.js和Ant Design 4.x,表单的提交可以通过使用Form组件的onFinish属性来实现。当表单的所有表单项都通过验证时,onFinish事件会被触发,并且会将表单的值作为参数传递给事件处理函数。下面是一个简单的例子,展示了如何在React.js和Ant Design 4.x提交表单。 首先,在你的代码导入所需的模块: ```js import React, { useState } from 'react'; import { Form, Input, Button } from 'antd'; ``` 接下来,创建一个表单组件: ```js const MyForm = () => { // 定义表单项的值 const [form] = Form.useForm(); // 表单提交事件 const handleSubmit = (values) => { console.log('Received values of form: ', values); // 在这里可以提交表单数据到服务器 }; return ( <Form form={form} onFinish={handleSubmit}> <Form.Item label="Username" name="username" rules={[{ required: true, message: 'Please input your username!' }]}> <Input /> </Form.Item> <Form.Item label="Password" name="password" rules={[{ required: true, message: 'Please input your password!' }]}> <Input.Password /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit"> Submit </Button> </Form.Item> </Form> ); }; ``` 在这个例子,我们使用了Ant Design的Form、Input和Button组件来创建表单。在表单,我们定义了一个onFinish事件处理函数handleSubmit,当表单的所有表单项都通过验证时,该事件会被触发。在事件处理函数,我们可以获取到表单的值,并将其提交到服务器。 最后,我们将表单组件渲染到页面: ```js ReactDOM.render(<MyForm />, document.getElementById('root')); ``` 这是一个简单的例子,你可以根据自己的需求来添加更多的表单项和验证规则。希望对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值