一: 表单验证:
相较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的官网有这样一段描述“”
-
你不再需要也不应该用
onChange
来做数据收集同步(你可以使用 Form 的onValuesChange
),但还是可以继续监听onChange
事件。 -
你不能用控件的
value
或defaultValue
等属性来设置表单域的值,默认值可以用 Form 里的initialValues
来设置。注意initialValues
不能被setState
动态更新,你需要用setFieldsValue
来更新。 -
你不应该用
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: () => { }
})
}
}