react项目经验

调用后返回上一页&&跳转至当前页

 this.props.history.goBack();   返回
 this.props.history.push("/index/setting/basicsetting"); 跳转
 this.props.history.go(-1)  跳转

当使用时出现以下错误Cannot read property 'push' of undefined,
因为父组件调用子组件定义的跳转事件时,要传递history,这里history未定义
(比如app.js这个组件,一般是首页,不是通过路由跳转过来的,而是直接从浏览器中输入地址打开的,如果不使用withRouter此组件的this.props为空,没法执行props中的history、location、match等方法)
解决方法:
import React from "react";
import {withRouter} from "react-router-dom";   //第一,引入withRouter

class MyComponent extends React.Component {   
  ...
  myFunction() {
    this.props.history.push("/some/Path");
  }
  ...
}
export default withRouter(MyComponent);   //第二,不要在上面暴露模块,在这里使用withRouter暴露模块

详细可见:react-router v4 使用 history 控制路由跳转   https://github.com/brickspert/blog/issues/3

调用后重新渲染当前页&&跳转至当前页

 this.props.history.go(0)  跳转



 state={
   visible:false
 }
 handleClick=()=>{
    this.setState({
       visible:true
     });
   }
 this.setState(this.state)  //此语句执行过后页面重新渲染state。这里需要注意的事重新渲染会将visible渲染成state里的false,而不是handleClick里的true
//渲染会把state里的内容全部重新渲染,即执行this.setState(state)之后,visible会被重新渲染为false,若需要visible为true,可以在渲染之后重新定义状态,如下重新定义
 this.setState({this.state})
 this.setState({
      visible:true
   });



 定义componentWillMount=async()=>{   
        this.getData(); //重新渲染当前页面
    }  // 使用:调用this.getData();函数即可
    async getData(){
        代码段
    }

代码解析

let {state}=this;  // 即 let state = this.state;

let res = await api.SettingGetInfo(this.props.match.params)   //获取列表里当前元素的id值,此方法需要注意有一个必要条件在route页面里的route添加  /:id
//即<Route path="/index/setting/basicsetting/:id" component={BasicSettting} />


rowKey={record=>record.id}    //表格table中的每个记录应该有唯一的“key”支持,或者将“rowKey”设置为唯一的主键,否则会报错。这里是给表格设置rowKey

点击按钮复制相关内容(这里以复制链接为例)

  npm i --save copy-to-clipboard   //首先安装相关包

  import copy from 'copy-to-clipboard';  //引入模块

  render:(a, code, index)=>{
                return <span>
                    <a href="# "  onClick={()=>{this.copyLink(code)}}>复制链接</a>
                </span>
            }

  copyLink=(code)=>{
        copy(`https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=${code.info}`)
        message.success("链接复制成功",2.5)
    }

三目运算符的嵌套使用

正常使用:code.type===1?(adate<bdate?atime:btime):<span className="text-success">永不</span>

react里:{title:"时间",dataIndex:"Time",render(a,code,index){
                let adate=...;
                let bdate=...;
                var overtime=<span className="text-danger">时间不足</span>;
                var forevertime=<span className="text-success">永久</span>
                var times=`${date.getFullYear()}-${date.getMonth() + 1<10?"0"+(date.getMonth()+1):date.getMonth()+1}-${date.getDate()<10?"0"+date.getDate():date.getDate()} ${date.getHours()<10?"0"+date.getHours():date.getHours()}:${date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()}:${date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()}`   //将时间戳转换为日期格式

                return <span>{code.type===1?(adate<bdate?overtime:times):forevertime}</span>  //嵌套使用
            }}

======================================================================================================================================================

接口部分

读懂接口文档


/api/wechat/code/:officialId/:qrcodeId  带冒号,动态数据:`${base}/api/wechat/code/${localStorage.getItem("listid")}/${params.id}`  //这列的:qrcodeId需要使用${params.id}动态写入,params即数组
/api/wechat/statistics/:officialId/code  不带冒号,静态的:`${base}/api/wechat/statistics/${localStorage.getItem("listid")}/code`  //这里的qrcode直接写上去就可以
 

参数问题

  request<T = any>(config: AxiosRequestConfig): AxiosPromise<T>;   //request 一个参数  config
  get<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;  //get  两个参数 url config
  delete(url: string, config?: AxiosRequestConfig): AxiosPromise;  //delete  两个参数  url config
  head(url: string, config?: AxiosRequestConfig): AxiosPromise;   //head  两个参数 url config
  post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;  //post 三个参数 url data config
  put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; // put 三个参数 url data config
  patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; // patch 三个参数 url data config

参数解释 :url —— 请求地址
                   data——发送给服务器的请求数据
                   config——配置,一般都是固定格式

举个栗子:
  export default{
        async codeDesign(params){                                                 
                return await axios.put(`${base}/api/code/${localStorage.getItem("listid")}/${params.id}`, params,{  //url data
                          headers:{                         //config  一般都是固定格式
                               "token":cookie.load("usertoken")
                          }
                }).then((res)=>{
                      return res.data;
                });
       },
        async codeExtend(params){
        return axios.post(`${base}/api/code/${localStorage.getItem('listid')}/${params.id}/extend`,{},{   //这里data就没有传参,而是用{}表示
            headers:{
                "token":cookie.load("usertoken")
            }
        }).then((res)=>{
            return res.data;
        });
    },
      async codeGetMsg(params){
              return await axios.get(`${base}/api/code/${localStorage.getItem("listid")}/${params.id}`,{
                  params,       **//如果是get delete两个参数的这种,是没有data参数的,那么params不能放在data里,就可以放在config里**
                  headers:{
                      "token":cookie.load("usertoken")
                  }
              }).then((res)=>{
                  return res.data;
              });
          },
  }

注意:需要的参数,一个都不能少,data如果不需要传,设置为{}都行,也不能不传

axios实战举例

state={

    //上传接口的参数
    title:"",   
    author:"",
    digest:"",
    content:"",

    piclist:[],   //从服务器获取的图片数组
    picTotal:2,   
    filter:{         
        isloading:false,
        type:"image",
        flag:2,
        page:1,
        pageSize:18,
      },
}

//上传pictextData数据到服务器
    addPictext=async()=>{
        let {title,author,digest,content}=this.state.pictextData;
        if(!title){
            this.setState({
                pictextTitleRemind:true
            })
            return;
        }else{
            this.setState({
                pictextTitleRemind:false
            })
        }
        if(!(/^(((https?):\/\/|\w+(\.\w+)+)(:\w+)?).*/.test(contentSourceUrl))){   //匹配正则
            this.setState({
                urlRemind:true
            })
            return;
        }else{
            this.setState({
                urlRemind:false
            })
        }
        let data=await api.pictextAdd({
            title,
            author,
            digest,
            content,
        })
        if(data.code!==0){
            console.log(api.stateCode[data.code]);
            return;
        }
        if(data.code===0){
            message.success("保存成功!",3);
            this.props.history.push("/index/setting/pictextIndex");
        }
    }

componentWillMount=async()=>{   //render加载之前就获取到图片信息
      this.getData();
    }

//获取图片的接口
async getData(){
      this.setState({
        filter: Object.assign(this.state.filter, {
            isloading: true
        }),
        
      });
      let res=await api.picGetList(this.state.filter)
     this.setState({
        filter: Object.assign(this.state.filter, {
            isloading: false
        }),
      if(res.code===0){
        this.state.picTotal=res.data.total;
        this.state.piclist=res.data.data;
      }else{
        console.log(api.stateCode[res.code]);
      }
      this.setState(this.state);  //重新渲染页面
    }

//分页
    onChangePage = (page = 1, pageSize = 18) => {
      this.setState(
          Object.assign(this.state.filter, {
              page,pageSize
          })
      );
      this.getData();  //重新加载getData函数,为了重新渲染页面
    }

//删除图片接口
    deletePic=async(item)=>{
      this.setState({
        imgDelete:false,
        picImgDelete:false,
      })
      let data=await api.picDelete({
        id:item.id,    //获取需要删除的图片的id
      })
      if(data.code!==0){
        console.log(api.stateCode[data.code]);
        return;
      }else if(data.code===0){
        this.onChangePage();
        message.success(`删除成功!`,2.5);
      }
      this.getData();
    }

<Pagination hideOnSinglePage onChange={this.onChangePage} current={this.state.filter.page} pageSize={this.state.filter.pageSize} total={this.state.picTotal}  />  //antd分页页标

受控组件和不受控组件

在HTML中,<textarea> 的值是通过子属性设置的。在React中,需要通过value设置。我们可以通过添加事件属性onChange监听内容的变化,onChange会在下列情况下被触发:
input或者textarea的内容改变
input的checked状态改变
select的状态改变

【受控组件】
设定了value的input就是一个受控组件。input里会一直展现这个值,用户的任何输入都是无效的。如果你想随着用户的输入改变,使用onChange事件,或者将value改为defaultValue

【非受控组件】
value没有值或者值设为null的input是一个不受控组件。用户的任何输入都会反映到输入框中
这个时候也可以监听onChange事件,内容的改变也会触发事件。
可以通过defaultValue给input设置默认值

指定编辑(如删除,更新等)

有一种需求是点击table中当前tr的“编辑”按钮后,跳转到新的编辑页面编辑当前tr的信息。
这种情况是需要动态获取id的
方法如下:
1、在route.js即路由页面将编辑页面的路由给一个/:id,如下
<Route path="/index/setting/code/code-edit/:id" component={codeEdit} />   //注意是/:id  /别忘了
2、列表页面编辑按钮的Link跳转给一个动态id(该id由后端接口数据里给出),如下
<Link to={`/index/setting/code/code-edit/${codelist.id}?id=${codelist.id}`} className="mr-10px">编辑</Link>
3、在编辑页面对接接口时,参数应使用this.props.match.params
async getPictextData(){
        let res =await api.pictextGetEdit(this.props.match.params)   //这里传入的是this.props.match.params
        if(res.code===0){
            state.pictextEditData=res.data;
        }else{
            console.log(api.stateCode[res.code]);
        }
        this.setState(state)
      }

提个醒:this.props.match.params是从另一个页面通过路由带到当前页面的数据。你可以在任何地方使用它。
这也表明了,这个传递的数据,不一定得是id,也可以是其他的数据。比如name,size等,通过/:name就可以传递
就比如说console.log(this.props.match.params)打印出来的是{"id":"1"}。你就可以通过this.props.match.params.id来获取到1。
但有一点,这个1可能是字符串类型的。和number类型的不是一个数据类型。所以在做判断是否相等的时候要注意,用==而不用===
在控制台打印出的数字,黑色的就是string类型。蓝色的是number类型

使用搜索框搜索数据(后端接口没有设置好,全部由前端操作)

state={
    filter: {
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
}

handleProductSearch=(e)=>{
        this.setState(
            Object.assign(this.state.filter,{
                name:e.target.value,   //在对接接口之后。若想根据名称name搜索,将搜索框的event赋值给filter里的name便可
            })
        );
        this.setState(state);  //重新渲染页面
    }


<Search
    placeholder="请输入产品名称"
    onSearch={this.handleProductSearch}
/>

使用搜索框搜索数据,(后端接口已经设置好的情况下)

state={
    filter: {
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
}

productName=(e)=>{
     this.setState(
            Object.assign(this.state.filter,{
                name:e.target.value,   //在对接接口之后。若想根据名称name搜索,将搜索框的值赋值给filter里的name便可
            })
        );
}

handleProductSearch=(e)=>{
        this.productInfoGet();  //调用获取产品信息的接口。此时的name已经是搜索的name。给接口接口会返回搜索后的结果
    }


<Search
    placeholder="请输入产品名称"
    onChange={this.productName}
    onSearch={this.handleProductSearch}
/>

======================================================================================================================================================

localStorage解释

    localStorage.setItem("key","value");//以“key”为名称存储一个值“value”

    localStorage.getItem("key");//获取名称为“key”的值

    localStorage.removeItem("key");//删除名称为“key”的信息。

    localStorage.clear();​//清空localStorage中所有信息

state里的filter里得数据怎么setState?(使用Object.assign相关知识)

this.state={
            visible:false,
            filter: {
                isloading: false,
                name:"",
                page:1,
                pageSize:20,
            }
        }

这里的isloading怎么设置为true呢?

handleClick=()=>{
        this.setState({
            filter:Object.assign(this.state.filter,{
                isloading:true
            }),
        });
    }

动态添加css样式(如通过点击添加css样式)

state={
    select: "",
}

handleSelect=(item)=>{
    this.setState({
        select: item.id
    })
}

<div onClick={()=>{this.handleSelect(item)}}  style={{border:this.state.select===item.id?"1px solid #28a745":null}}></div> 

动态添加一组可编辑框(如点击添加按钮后会添加一个可输入数值的图文框)

思路:
1、state一个数组如Data,将数组的值与图文框绑定起来,通过map函数渲染到页面
2、当点击添加按钮后,执行函数,往list数组里push一组数据,数据会自动渲染到页面,即实现了动态添加图文框的功能
3、通过编辑数组的值即可动态编辑图文框里的内容
4、动态删除可以通过用数组的splice操作数组的下标index来实现删除。
总结:通过操作数组的数据来实现图文框的增删改,而不是通过dom操作

举个例子:
state={
    title:"",     //上传接口的参数
    author:"",
    digest:"",
    content:"",
    Data:[{id:"1",title:"",author:"",digest:"",content:""}],
    boxid:"1", //定义图文框的id
    msg:[],
    changeBorder:"",
}

//添加图文框数组
    addBox=()=>{
        this.setState({
            boxid:this.state.boxid++, 
        })
        this.state.Data.push({id:`${this.state.boxid}`,title:"",author:"",digest:"",content:""})
        this.setState(this.state)
    }
//删除图文框
listbox_Delete=(item)=>{  
        let index= this.state.Data.indexOf(item)    //获取需要删除的图文框的index
        this.state.Data.splice(index,1)    //使用splice方法删除数组数据
    }

//向上移动图文框(通过改变替换index来实现)
listbox_up=(item)=>{
        let index=this.state.Data.indexOf(item)
        let arr=this.state.Data
        let index2=index-1
        if(index2!==0){
            arr[index]=arr.splice(index2,1,arr[index])[0] 
        } 
    }

//向下移动图文框
listbox_down=(item)=>{
        let index=this.state.Data.indexOf(item)
        let arr=this.state.Data
        let index2=index+1
        if(index2!==arr.length){
            arr[index]=arr.splice(index2,1,arr[index])[0]
        }
    }

//图文框数组map方式渲染到页面
{
         this.state.Data.map((item,index)=>{
         if(item.id==1){   //item.id==1时是主图文框的样式,否则是副图文框的样式
         return <div onClick={()=>{this.handleSelect(item)}} key={index}>   //map语法必须要带有key={index},不然会报错
                         <div  >
                             <img src={item.picUrl} alt="" style={{width:"100%",height:"100%"}}/>
                         </div>
                         {item.title?<div className="indexbox_mask">{item.title}</div>:null}
                     </div>
                  }else{
               return <div  key={index} style={{border:this.state.changeBorder===item.id?"2px solid #28a745":null}} onClick={()=>{this.handleSelect(item)}}>    //handleSelect,点击后选取当前框并与输入框绑定
                              <h4 style={{height:21}}>{item.title}</h4>
                              <div className="listbox_content">
                                    <div className="listbox_img">
                                            <img src={item.picUrl} alt=""/>
                                    </div>
                              </div>
                              <div className="listbox_mask">
                                      <Icon type="up"className="listbox_icon mr-10px" onClick={()=>{this.listbox_up(item)}} />  //图文框位置上移
                                      <Icon type="down" className="listbox_icon" onClick={()=>{this.listbox_down(item)}} />  //图文框位置下移
                                      <div className="float-r">
                                           <Icon type="delete"className="listbox_icon" onClick={()=>{this.listbox_Delete(item)}}/>   //删除图文框
                                      </div>
                               </div>
                          </div>
                       }
                 })
             }
    <Button onClick={this.addBox}></Button>  //添加图文框

//点击图文框后选定当前图文框,并与Input输入框绑定,之后在Input里输入的值都会存在当前数组里。再点击其他图文框后执行同样的操作,最后所有图文框里采集的数据会全部存在Data数组里,通过接口将数组传入后台,再在另一个页面获取并渲染该组数据,即完成了前后端的一个交接流程。
handleSelect=(item)=>{
        console.log(item)
        this.setState({
            msg:item,
            changeBorder:item.id,
            title:item.title,
            author:item.author,
            digest:item.digest,
            content:item.content,
        })
    }

handleGetTitle=(e)=>{     //与Input标签之间进行双向绑定
        this.setState({
            title:e.target.value,
        })
        this.state.msg.title=e.target.value;    //使得输入框与当前选定的文本框绑定
    }

<Input  onChange={this.handleGetTitle} id={this.state.msg.id} value={this.state.title} placeholder="请输入标题"/>

antd图片上传

//判断用户上传文件的格式,不符合提醒用户,符合则返回true
function beforeUpload(file) {
  if(file.type!=='image/png'&&file.type!=='image/jpeg'&&file.type!=='image/jpg'&&file.type!=='image/gif'){
    message.error("上传失败!仅支持jpeg,png,jpg,gif图片格式");
    return false;
  }else if(file.size/1024/1024>4){
    message.error("上传失败!仅支持大小在4M以内的图片上传");
    return false;
  }
  return true;
}

//上传图片接口
    UploadImg=()=>{
      let self= this;    
      return {
        name: 'media',
        action: `  `,  //这里写服务器地址
        headers: {    //设置请求头
          token: cookie.load('usertoken'),
        },
        onChange(info) {
          self.setState({
            uploadWaiting:true
          })
          if (info.file.status !== 'uploading') {
            console.log(info.file, info.fileList);
            self.setState({
              uploadWaiting:false,
            })
          }
          if (info.file.status === 'done') {
            message.success(`${info.file.name}上传成功!`);
            self.setState({
              uploadWaiting:false,
            })
            self.getData()
          } else if (info.file.status === 'error') {
            message.error(`${info.file.name}上传失败!`);
            self.setState({
              uploadWaiting:false,
            })
          }
        },
      }
    }

    <Upload {...this.UploadImg()} beforeUpload={beforeUpload}><Button>上传图片</Button></Upload>

列表数据相关操作(table)

constructor(props){
        super(props);
        this.columns=[
            {title:"",
            dataIndex:"ticket",
            width:66,
            render:(record)=>(<img src={record} width="50px" alt="" />)    
            },
            {title:"产品名称",dataIndex:"name"},
            {title:"产品类型",dataIndex:"type", render(a, productlist, index){
                return <span>{productist.type || "无"}</span>
            }},
            {title:"对应编码",dataIndex:"keyword"},
            {title:"生产时间",dataIndex:"createtime"},
            {title:"到期时间",dataIndex:"expiretime",render(a,productlist,index){
                let date=new Date(new Date(productlist.expireTime).getTime());
                let nowdate=new Date(new Date().getTime());
                var overtime=<span className="text-danger">已过期</span>;
                var forevertime=<span className="text-success">永不</span>
                var times=`${date.getFullYear()}-${date.getMonth() + 1<10?"0"+(date.getMonth()+1):date.getMonth()+1}-${date.getDate()<10?"0"+date.getDate():date.getDate()} ${date.getHours()<10?"0"+date.getHours():date.getHours()}:${date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()}:${date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()}`
                return <span>{productlist.mode===1?(date<nowdate?overtime:times):forevertime}</span>
            }},
            {title:"操作",
            dataIndex:"operation",
            key:"operation",
            width:225,
            render:(a, qrcodelist, index)=>{
                return <span>
                    <a href="# " className="mr-10px" onClick={()=>{this.copyLink(qrcodelist)}}>复制链接</a>
                    <a href={`${productlist.ticket}`} target={"_blank"} download={`${productlist.name}`} className="mr-10px">下载产品</a>
                    <Link to={`/index/setting/product/product-edit/${productlist.id}?id=${productlist.id}`} className="mr-10px">编辑</Link>
                    {productlist.mode===2 ? <a href="# "  onClick={()=>{this.showModal2(productlist)}}>删除</a> : <a href="# " onClick={() => {this.extendProduct(productlist)}}>延时上架</a>}
                </span>
            }
            
        },
        ];
        this.state={
            visible:false,
            visible2:false,
            productlist:[],
            filter: {
                isloading: false,
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
        }
        
    }


<Table 
  columns={this.columns} 
  dataSource={this.state.productlist} 
  rowKey={record=>record.id}    //表中的每个记录应该有唯一的“key”支持,或者将“rowKey”设置为唯一的主键,否则会报错。这里是给表格设置rowKey
  pagination={{onChange:this.onChangePage, current: this.state.filter.page, pageSize: this.state.filter.pageSize , total: this.state.filter.total }} /> 

注意:这里涉及到两种render写法,两种写法的this指向不同,其他效果差不多
1、render:(a,b)=>{
            let time=a,
            let overtime=b,
            return <div>......</div>
       }
2、render(a,b){
        let time=a,
        let overtime=b,
        return <div>......</div>
    }
                        

滚动监听及回到顶部

state={
    backTop:false,
    backTopShow:false,
}

componentWillMount=()=>{
        window.addEventListener("scroll",this.handleScroll,true)    //滚动监听
    }

handleScroll=()=>{
        if(document.documentElement.scrollTop>1000){
            this.setState({
                backTopShow:true,    //当滚动到距离顶部1000px的距离时,“回到顶部”按钮显示
            })
        }else{
            this.setState({
                backTopShow:false,
            })
        }
        if(document.documentElement.scrollTop===0){   //当滚动到 0时,清除定时器
            clearInterval(this.scrollTimes)
        }
    }

backToTop=()=>{
        if(document.documentElement.scrollTop>0){
            this.scrollTimes=setInterval(()=>{
                document.documentElement.scrollTop=document.documentElement.scrollTop-60;
            },5)
        }
    }


{this.state.backTopShow?<Button onClick={this.backToTop}>回到顶部</Button>:null}    //“回到顶部”按钮

关于接口调用函数的写法

间接调用,被动触发式用这种写法,这种写法用onClick等主动触发可能会引起Cannot read property 'setState' of undefined错误
async userInfoGet(){
        let res=await api.getUserInfo()
        if(res.code===0){
            this.setState({
                userNickname:res.data.nickname
            })
        }else{
            console.log(api.stateCode[res.code]);
        }
    }
componentWillMount(){
    this.userInfoGet()
}  //在别的函数里间接触发
直接调用,主动触发式如onClick等,用这种写法
userInfoGet=async()=>{
        let res=await api.getUserInfo()
        if(res.code===0){
            this.setState({
                userNickname:res.data.nickname
            })
        }else{
            console.log(api.stateCode[res.code]);
        }
    }
<Button onClick={this.userInfoGet}></Button>  //主动调用

将React.Component外部的代码移入到其内部

外部:
const props = {
  name: 'file',
  action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
  headers: {
    authorization: 'authorization-text',
  },
  onChange(info) {
    if (info.file.status !== 'uploading') {
      console.log(info.file, info.fileList);
    }
    if (info.file.status === 'done') {
      message.success(`${info.file.name} file uploaded successfully`);
    } else if (info.file.status === 'error') {
      message.error(`${info.file.name} file upload failed.`);
    }
  },
};

export default class Demo extends React.Component{}

内部:
export default class Demo extends React.Component{
    state={}
    pluginZipUpload=()=>{
        let self=this;    //这里改动 let self=this
        return{   //这里改动return
            name: 'plugin',
            action: "https://www.mocky.io/v2/5cc8019d300000980a055e76",
            headers:{
                authorization: 'authorization-text',
            },
            onChange(info) {
              if (info.file.status !== 'uploading') {
                console.log(info.file, info.fileList);
              }
              if (info.file.status === 'done') {
                self.setState({
                    pluginAddFile:Object.assign(self.state.pluginAddFile,{     //这里this换成self
                        plugin: info.file.originFileObj
                    })
                })
                console.log(self.state.pluginAddFile.plugin)
              } else if (info.file.status === 'error') {
                message.error(`${info.file.name}上传失败`);
              }
            },
        }
      };

}

如何知道函数里需要传几个参数或者判断函数里有几个参数

es5里可以用arguments打印
es6里可以用拓展运算符...a方法
在函数里写入...params
handleUpload=(...a)=>{}
console.log(...a)即可打印出来里面需要的参数

可搭配debugger使用
posted @ 2019-05-25 10:14  huihuihero  阅读(1871)  评论(0编辑  收藏  举报