三、数据录入组件(2)

三、数据录入

1、Select选择器

下拉选择器。

何时使用:<1>弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。<2>当选项少时(少于 5 项),建议直接将选项平铺,使用 Radio 是更好的选择。

  • (0)<Select>组件对应的事件
    • <1>onBlur事件: 表示失去焦点时回调.可选值:无;默认值: -;类型: function。
    • <2>onChange事件: 表示选中 option,或 input 的 value 变化(combobox 模式下)时,调用此函数.可选值:无;默认值: -;类型: function(value, option:Option/Array)。
      • value: 为选中的option的value值。类型为字符串或者数组,如果是多选,这个value就是一个数组
      • option: 对应的选中的option对象。样式为 {key: 'aaa', props: {children: 'text', value: 'value11'}},key就为当前option的key,children就为当前option的内容,value就为当前option的value
    • <3>onDeselect事件: 表示这个也是一个神事件呀!!在取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效。在取消选中的情况下,会先触发这个,再触发上面那个onChange.可选值:无;默认值: -;类型: function(string|number|LabeledValue)。
    • <4>onFocus事件: 表示获得焦点时回调.可选值:无;默认值: -;类型: function。
    • <5>onInputKeyDown事件: 表示按键按下时回调.可选值:无;默认值: -;类型: function。
    • <6>onMouseEnter事件: 表示鼠标移入时回调.可选值:无;默认值: -;类型: function。
    • <7>onMouseLeave事件: 表示鼠标移出时回调.可选值:无;默认值: -;类型: function。
    • <8>onPopupScroll事件: 表示下拉列表滚动时的回调.可选值:无;默认值: -;类型: function。
    • <9>onSearch事件: 表示文本框值变化时回调.可选值:无;默认值: -;类型: function(value: string)。
    • <10>onSelect事件: 表示被选中时调用,参数为选中项的 value (或 key) 值.可选值:无;默认值: -;类型: function(string|number|LabeledValue, option:Option)。
    • <11>onDropdownVisibleChange事件: 表示展开下拉菜单的回调。这个事件还是很好用的,当用dropdownRender把下拉框取消了之后,如果想要实现点击select的时候触发一个函数,由于是不能用onClick的,所以就只有用这个onDropdownVisibleChange事件来实现点击了.可选值:无;默认值: -;类型: function(open)。
  • (1)<Select>组件对应属性:
    • <1>allowClear: 表示选择了option之后,在后面出现一个×,点击可以清空select的value为undefined.可选值:无;默认值: false;类型: boolean。
    • <2>autoClearSearchValue: 表示是否在选中项后清空搜索框,只在 mode 为 multiple 或 tags 时有效.可选值:无;默认值: true;类型: boolean。
    • <3>autoFocus: 表示默认获取焦点.可选值:无;默认值: false;类型: boolean。
    • <4>defaultActiveFirstOption: 表示是否默认高亮第一个选项.可选值:无;默认值: true;类型: boolean。
    • <5>defaultValue: 表示指定select框,默认选中的option的value值.可选值:无;默认值: -;类型: string|string[]
      number|number[]
      LabeledValue|LabeledValue[]。
      • 当select框的mode为multiple的时候,这个defaultValue的值需要为一个数组。普通情况下,一个字符串就好了
    • <6>disabled: 表示是否禁用.可选值:无;默认值: false;类型: boolean。
    • <7>dropdownClassName: 表示下拉菜单的 className 属性.可选值:无;默认值: -;类型: string。
    • <8>dropdownMatchSelectWidth: 表示下拉菜单和选择器同宽.可选值:无;默认值: true;类型: boolean。
    • <9>dropdownRender: 表示自定义下拉框内容,可以实现点击select框的时候,下面弹出来的内容为空.可选值:无;默认值: -;类型: (menuNode: ReactNode, props) => ReactNode。
      • <Select mode='multiple' dropdownRender={()=>{return <span></span>;}}></Select>,这样配置,点了select框之后,下面依然不会弹出东西来
    • <10>dropdownStyle: 表示下拉菜单的 style 属性.可选值:无;默认值: -;类型: object。
    • <11>dropdownMenuStyle: 表示dropdown 菜单自定义样式.可选值:无;默认值: -;类型: object。
    • <12>filterOption: 表示是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false。当用select做搜索和远程数据结合的时候需要把这个值设置为false.可选值:无;默认值: true;类型: boolean or function(inputValue, option)。
    • <13>firstActiveValue: 表示默认高亮的选项.可选值:无;默认值: -;类型: string|string[]。
    • <14>getPopupContainer: 表示菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位.可选值:无;默认值: () => document.body;类型: Function(triggerNode)。
    • <15>labelInValue: 表示是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 string 变为 {key: string, label: ReactNode} 的格式.可选值:无;默认值: false;类型: boolean。
    • <16>maxTagCount: 表示最多显示多少个 tag.可选值:无;默认值: -;类型: number。
    • <17>maxTagTextLength: 表示最大显示的 tag 文本长度.可选值:无;默认值: -;类型: number。
    • <18>maxTagPlaceholder: 表示隐藏 tag 时显示的内容.可选值:无;默认值: -;类型: ReactNode/function(omittedValues)。
    • <19>mode: 表示设置 Select 的模式为多选或标签。设置了这个之后,select框就没有最后面那个箭头了,并且可以在select框里面输入字符串.可选值:无;默认值: -;类型: ‘multiple’ | ‘tags’ 。
      • multiple模式下,选中的option会以一个tag的形式出现在select框里面,可以点×取消掉。并且在select框里面输入的字符串,会匹配下面的option选项,匹配不到就显示为空
      • tags模式和multiple差不多,不过在select框里面输入的字符串的时候,不是匹配下面的option了,而是输入什么下面就出现什么,选中下面的值之后,会以一个tag的形式,出现在select框里面
    • <20>notFoundContent: 表示这个很重要。当下拉列表为空时显示的内容。当用select做搜索和远程数据结合的时候需要把这个值设置为null.可选值:无;默认值: ‘Not Found’;类型: string。
      • notFoundContent={null}
    • <21>optionFilterProp: 很重要,需要配合下面的showSearch属性一起使用。表示当在select框里面输入了字符串之后,这个输入的字符串匹配的是当前option的哪个属性。默认为匹配option的value;设置值为children,就是匹配option里面的内容了.可选值:value/children;默认值: value;类型: string。
    • <22>optionLabelProp: 表示回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 value.可选值:无;默认值: children (combobox 模式下为 value);类型: string。
    • <23>placeholder: 表示选择框默认文字,在有defaultValue的时候会失效.可选值:无;默认值: -;类型: string。
    • <24>showArrow: 表示是否显示下拉小箭头.如果设置为了false,那么用suffixIcon属性自定义的小图标,也不会显示了.可选值:无;默认值: true;类型: boolean。
    • <25>showSearch: 表示使单选模式可搜索,即在select框里面可以输入字符串,下面就会匹配对应的option出来。需要配合上面的optionFilterProp属性来一起使用.可选值:无;默认值: false;类型: boolean。
    • <26>size: 表示选择框大小,可选 large small。三种大小的选择框,当 size 分别为 large 和 small 时,输入框高度为 40px 和 24px ,默认高度为 32px.可选值:无;默认值: default;类型: string。
    • <27>suffixIcon: 表示自定义的选择框后缀图标.可选值:无;默认值: -;类型: ReactNode。
    • <28>removeIcon: 表示自定义的多选框清除图标.可选值:无;默认值: -;类型: ReactNode。
    • <29>clearIcon: 表示自定义的多选框清空图标.可选值:无;默认值: -;类型: ReactNode。
    • <30>menuItemSelectedIcon: 表示自定义多选时当前选中的条目图标.可选值:无;默认值: -;类型: ReactNode。
    • <31>tokenSeparators: 表示在 tags 和 multiple 模式下自动分词的分隔符.可选值:无;默认值: -;类型: string[]。
    • <32>value: 表示指定当前选中的条目.可选值:无;默认值: -;类型: string|string[]
      number|number[]
      LabeledValue|LabeledValue[]。
    • <33>defaultOpen: 表示是否默认展开下拉菜单.可选值:无;默认值: -;类型: boolean。
    • <34>open: 表示是否展开下拉菜单.可选值:无;默认值: -;类型: boolean。
    • <35>loading: 表示让select框的最后一直出现转圈圈的那个,加载中状态.可选值:无;默认值: false;类型: boolean。
  • (2)<Select>的子组件<Select.Option>选择框的每一个选项对应属性:
    • <1>disabled: 表示是否禁用.可选值:无;默认值: false;类型: boolean。
    • <2>key: 表示和 value 含义一致。如果 React 需要你设置此项,此项值与 value 的值相同,然后可以省略 value 设置。这个key是必须要弄成属性加在option上面的,不能像table那样直接把key放在数据里面,因为select不会直接把数据放在datasource上.可选值:无;默认值: -;类型: string。
    • <3>title: 表示选中该 Option 后,Select 的 title.可选值:无;默认值: -;类型: string。
    • <4>value: 表示option的唯一标识符,默认根据此属性值就可以筛选出对应的option.可选值:无;默认值: -;类型: string|number。
    • <5>className: 表示Option 器类名.可选值:无;默认值: -;类型: string。
  • (3)<Select>的子组件<Select.OptGroup>选择框的选项组对应属性: 对option进行分组,组名为label
    • <1>key: 表示****.可选值:无;默认值: -;类型: string。
    • <2>label: 表示组名.可选值:无;默认值: -;类型: string|React.Element。
import React, { PureComponent } from 'react';
import { Select } from 'antd';
const Option = Select.Option;
class demo extends PureComponent {
  handleChange(value:any,option:any) {console.log(`selected ${value}`, option);}
    render() {
    const searchFenceKeyArr = [{name: 2, id: 1}];
      return (
        <div>
        // 下面为一个普通的,可以进行筛选的select
         <Select
          showSearch
          optionFilterProp='children'
          placeholder="全部"
          allowClear
          value={dealerValue}
          onChange={value => {this.setState({dealerValue:value});}}
          style={
   
   {width: '100%'}}
        >
            {
              Object.keys(carSeriesListObj).map(brand => {
                return (
                  <Select.OptGroup key={brand} label={carSeriesListObj[brand][0].manufacturerName}>
                    {carSeriesListObj[brand].map(value => <Select.Option key={value.carTypeCode} value={value.carTypeCode}>{value.carTypeName}</Select.Option>)}
                  </Select.OptGroup>
                );
              })
            }
        </Select>
                
                
        // 下面这个select为做成搜索框的select
          <Select
            placeholder="请输入名称"
            showSearch
            // showArrow={false}
            filterOption={false}
            notFoundContent={null}
            suffixIcon={<Icon type="search" style={
   
   {cursor: 'pointer'}} onClick={this.debounce(()=>{this.searchFence()}, 50)} />}
            value={searchFenceValue}
            onChange={value=>{this.setState({searchFenceValue:value})}}
            onSearch={value => {this.searchMarkerPosition(value)}}
            className={styles.searchInp}
          >
            {searchFenceKeyArr.map(value => <Select.Option key={JSON.stringify(value)} value={JSON.stringify(value)}>{value.name}</Select.Option>)}
          </Select>
          
          // 下面这个是点击这个select框,就弹出另外一个modal,然后在modal里面进行数据的选择。选好了之后,在select里面显示出来
          <Select
            placeholder='请选择'
            allowClear
            mode='multiple'
            maxTagCount={10}
            dropdownRender={()=>{return <span></span>;}}
            maxTagPlaceholder={omittedValues => {return `......其余的 ${omittedValues.length} 个选中车系请点击查看`;}}
            onDropdownVisibleChange={()=>{
              if(form.getFieldsValue(['brand']).brand !== undefined && form.getFieldsValue(['brand']).brand.length !== 0){
                setCarSeriesSelectModalVisible(true);
                return;
              }
              message.error('请先选择品牌');
            }}
            onDeselect={value=>{
              cancelCarSeriseSelect(value); // 这个是清除单个选择的标签的时候,就调用这个
            }}
            onChange={value=>{if (value.length === 0) {setCarSeriesList([]);}}}
          >
            {carSeriesList.map(value => <Select.Option key={value.key} value={value.key}>{value.key}({value.value})</Select.Option>)}
          </Select>
        </div>
    );
    }
  };
export default demo;

2、TreeSelect树选择

树型选择控件。用于数据量较少时候的分级场景

何时使用:类似 Cascader级联选择器,不过cascader级联选择器的子元素是从右边弹出来的,而treeSelect是直接在当前目录的下面弹出来的,可以使用 TreeSelect,例如公司层级、学科系统、分类目录等等。。还么看

3、Transfer穿梭框

双栏穿梭选择框。就是把左边东西移动到右边去,右边东西移动到左边去

何时使用:<1>需要在多个可选项中进行多选时。<2>比起 Select 和 TreeSelect,穿梭框占据更大的空间,可以展示可选项的更多信息。

  • (0)<Transfer>组件对应的事件
    • <1>onChange事件: 表示选项在两栏之间转移时的回调函数.可选值:无;默认值: -;类型: (targetKeys, direction, moveKeys): void。
      • targetKeys:移动之后,transfer中显示在右侧框的所有数据的key值数组
      • direction: 移动到的框的位置。类型 ‘right’ ‘left’
      • moveKeys: 被移动的key的数组。(key是dataSource里面的key)
    • <2>onScroll事件: 表示选项列表滚动时的回调函数.可选值:无;默认值: -;类型: (direction, event): void。
      • direction: 当前发生滚动的框的位置。类型 ‘right’ ‘left’
    • <3>onSearch事件: 表示搜索框内容时改变时的回调函数.可选值:无;默认值: -;类型: (direction: ‘left’|‘right’, value: string): void。
    • <4>onSelectChange事件: 表示选中项发生改变时的回调函数.可选值:无;默认值: -;类型: (sourceSelectedKeys, targetSelectedKeys): void。
      • sourceSelectedKeys: 左边框被选中的key的数组
      • targetSelectedKeys: 右边框被选中的key的数组
  • (-1)<Transfer>的数据里面的children自定义渲染列表对应的事件
    • <1>onItemSelect事件: 表示勾选条目.可选值:无;默认值: -;类型: (key: string, selected: boolean)。
    • <2>onItemSelectAll事件: 表示勾选一组条目.可选值:无;默认值: -;类型: (keys: string[], selected: boolean)。
  • (1)<Transfer>组件对应属性:
    • <1>className: 表示自定义类.可选值:无;默认值: -;类型: string。
    • <2>dataSource: 表示数据源,表示整个transfer里面的所有的数据,且默认渲染在左边一栏中;右边一栏中的数据是由targetKeys属性来决定.可选值:无;默认值: [];类型: TransferItem[]。
      • dataSource为一个数组,数组里面的每一项为一个数据对象,这些数据对象都会调用render来渲染为transfer左右框下面的元素。下面为数据对象的键值
        • key: 数据对象的key值。这个key值,用来代表这一个数据对象
        • title: 数据对象的title
        • description: 数据对象的描述
        • disabled: 是否禁用这一个数据对象
    • <3>disabled: 表示是否禁用.可选值:无;默认值: false;类型: boolean。
    • <4>filterOption: 表示接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false.可选值:无;默认值: (inputValue, option): boolean ;类型: -。
    • <5>footer: 表示底部渲染函数.可选值:无;默认值: -;类型: (props) => ReactNode 。
    • <6>lazy: 表示Transfer 使用了 react-lazy-load 优化性能,这里可以设置相关参数。设为 false 可以关闭懒加载.可选值:无;默认值: { height: 32, offset: 32 };类型: object|boolean。
    • <7>listStyle: 表示自定义左右两个穿梭框的样式.可选值:无;默认值: -;类型: object|({direction: ‘left’|‘right’}) => object。
      • object表示左右穿梭框对应的css样式对象。如:listStyle={ {width: 250,height: 300,}}
    • <8>locale: 表示各种语言.可选值:无;默认值: { itemUnit: ‘项’, itemsUnit: ‘项’, searchPlaceholder: ‘请输入搜索内容’ };类型: { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; }。
    • <9>operations: 表示连接左右两个框中间的按钮里面的文字数组。数组的第一项表示上面那个按钮,第二项表示下面那个数组.可选值:无;默认值: [’>’, ‘<’];类型: string[]。
    • <10>render: 表示dataSource中的每一项都会调用这个render函数,并且render函数的参数就为dataSource中的项,返回值为渲染到页面上的ReactElement,或者返回一个普通对象,其中 label 字段为 ReactElement,value 字段为 title(显示在页面上就为transfer左右框下面的元素).可选值:无;默认值: -;类型: (dataItem) => ReactNode。
    • <11>selectedKeys: 表示transfer中被选中的项(多选框为被选中),的key(依然表示dataSource中的key)值数组.可选值:无;默认值: [];类型: string[]。
    • <12>showSearch: 表示在左边框和右边框都显示一个搜索框,可以在搜索框里面对下面的数据进行搜索.可选值:无;默认值: false;类型: boolean。
    • <13>showSelectAll: 表示是否展示全选勾选框.可选值:无;默认值: true;类型: boolean。
    • <14>style: 表示容器的自定义样式.可选值:无;默认值: -;类型: object。
    • <15>targetKeys: 表示显示在右侧框的所有数据的key值数组;这个key值就是dataSource中,数据对象里面的key值.可选值:无;默认值: [];类型: string[]。
    • <16>titles: 表示transfer左边和右边框上面的标题;数组的第一项是左边框上面的标题,第二项是右边框上面的标题.可选值:无;默认值: [’’, ‘’];类型: ReactNode[]。
  • (2)<Transfer>的数据里面的children自定义渲染列表并返回以下参数:
    • <1>direction: 表示渲染列表的方向.可选值:无;默认值: -;类型: ‘left’ | ‘right’。
    • <2>disabled: 表示是否禁用列表.可选值:无;默认值: -;类型: boolean。
    • <3>filteredItems: 表示过滤后的数据.可选值:无;默认值: -;类型: TransferItem[]。
    • <4>selectedKeys: 表示选中的条目.可选值:无;默认值: -;类型: string[]。
import React, { PureComponent } from 'react';
import { Transfer, Switch, Icon } from 'antd';
class demo extends PureComponent {
  render() {const mockData = [];
    for (let i = 0; i < 20; i++) {mockData.push({key: i.toString(),title: `content${i + 1}`,description: `description of content${i + 1}`,disabled: i % 3 < 1,});}
    const oriTargetKeys = mockData.filter(item => +item.key % 3 > 1).map(item => item.key);
    return (<Transfer dataSource={mockData} titles={['Source22', 'Target111']} targetKeys={oriTargetKeys} selectedKeys={['0', '2', '3']} render={item => item.description} showSearch listStyle={
   
   { width: 500, height: 300, }} operations={['to right', 'to left']} disabled={false}/>);}
};
export default demo;

4、TimePicker时间选择框

和DatePicker对应,这个是选中时/分/秒的

何时使用:当用户需要输入一个时间,可以点击标准输入框,弹出时间面板进行选择。还么看

5、Upload上传

文件选择上传和拖拽上传控件。

何时使用:<1>当需要上传一个或一些文件时。<2>当需要展现上传的进度时。<3>当需要使用拖拽交互时。

  • (0)<Upload>组件对应的事件
    • <1>onChange事件: 表示上传文件改变时的状态;上传中(上传过程中由于数据不会一次全部上传完,所以有可能会多次触发、完成、失败、或者删除都会调用这个函数.可选值:无;默认值: -;类型: ({file,fileList,event}) => {}。
      • file: 表示当前操作的文件对象,不为h5的file对象。下面为file的属性
        • uid:file的id值。这个也很关键的,用来标识每个fileList里面的file,如果要删除,这个就很重要了
        • lastModified: 最近更新时间
        • name: 上传的文件的文件名
        • size: 上传的文件的大小
        • type: 上传文件的类型
        • percent: 上传文件的进度。最多100。 类型:string
        • originFileObj: 这个就代表上传的文件的file对象(h5的file对象)了。
        • status: 文件上传的状态。可选值:‘uploading’(上传中) ‘done’(上传完成) ‘error’ removed(删除)
          • done状态:当文件上传完成的时候会触发onChange事件,并且状态变为done。这时候就会在file上面有下面那个response属性了
          • removed状态:当点击filelist的删除按钮的时候会触发onChange事件,并且状态变为removed
        • response: 后台返回的数据。只有当状态为done的时候才会在file上面有这个属性
        • xhr: 对应的xhr对象
      • fileList: 展示在上传按钮下面的,上传列表中的所有file(非h5的file对象)的数组。
      • event: 这个event是ProgressEvent(上传进度事件),就可以从这个事件里面读取出上传的总数据和已经发送的数据(完美的解决了fetch不能读取进度事件的问题,就可以做进度条了)。属性如下
        • total: 总数据
        • loaded: 已上传的数据量
    • <2>onPreview事件: 表示点击上传按钮下面的,上传列表里面的文件链接或预览图标时的回调.可选值:无;默认值: -;类型: Function(file)。
    • <3>onRemove事件: 表示点击移除文件时的回调,返回值为 false 时不移除。支持返回一个 Promise 对象,Promise 对象 resolve(false) 或 reject 时不移除.可选值:无;默认值: -;类型: Function(file): boolean | Promise。
      • 这里就需要用到上面file的uid来从fileList找到对应的值了
    • <4>onDownload事件: 表示点击下载文件时的回调,如果没有指定,则默认跳转到文件 url 对应的标签页.可选值:无;默认值: 跳转新标签页;类型: Function(file): void。
  • (1)<Upload>组件对应属性: 组件里面必须包含其余的组件,代表显示在页面上面的upload的样式,不然就不会出现Upload的点击按钮
    • <1>accept: 表示接受上传的文件类型,为多个类型的字符串拼接形式,如accept=".xlsx, .xls"。设置了这个之后,上传文件的弹出框里面,就不会出现其它类型的文件,但是用户依然可以点击弹出框的右下角把所有文件弄出来,所以用这个来限制用户的输入类型,是不准的。详见 input accept Attribute.可选值:无;默认值: -;类型: string。
    • <2>action: 表示上传的地址.可选值:无;默认值: -;类型: string|(file) => Promise。
    • <3>method: 表示上传请求的 http method.可选值:无;默认值: ‘post’;类型: string
    • <4>directory: 表示把上传文件改为上传文件夹(caniuse),这个模式就不能上传文件了.可选值:无;默认值: false;类型: boolean。
    • <5>beforeUpload: 表示弹出框选择了文件之后,上传文件之前的钩子,参数为上传的文件,若返回 false 则选择的文件出现在文件列表里,但是停止上传。所以这个时候就可以用这个来实现,手动上传了(点击确定按钮才上传文件)。可以用来限制上传文件的类型和大小.可选值:无;默认值: -;类型: (file, fileList) => boolean | Promise。
      • 支持返回一个 Promise 对象,Promise 对象 reject 时则停止上传,resolve 时开始上传( resolve 传入 File 或 Blob 对象则上传 resolve 传入对象)
      • 实现手动上传,在beforeUpload钩子里面return出false,但是把对应的file存到state里面去,然后点击上传按钮的时候,再发送请求。
    • <6>customRequest: 表示通过覆盖默认的上传行为,可以自定义自己的上传实现。这个和上面哪个beforeUpload差不多的,依然是选择了文件之后开始触发.可选值:无;默认值: -;类型: (files)=>{}。 files里面有file
    • <7>data: 表示上传到后台所需的额外参数。这个很重要.可选值:无;默认值: -;类型: object|(file) => object。
    • <8>defaultFileList: 表示默认已经上传的上传按钮下面的文件列表.可选值:无;默认值: -;类型: Array[file,file]
    • <9>disabled: 表示是否禁用.可选值:无;默认值: false;类型: boolean。
    • <10>fileList: 表示已经上传的文件列表(受控),默认会展示出来。每个文件后面可以有预览、下载、删除这三个功能,具体哪些可用,就要看file里面有没有对应的字段了.可选值:无;默认值: -;类型: Array[file,file]。(表示一个数组,数组的每一项是一个file对象)
      • 这个fileList里面的可选属性如下: {uid: '1',name: 'xxx.png',status: 'done',url: 'http://www.baidu.com/xxx.png',thumbUrl: 'https://zo.png',}。file对象没有status属性的话,就没有下载按钮;file对象没用url属性的话,就没有预览按钮,也没有预览的图片了。
    • <11>headers: 表示设置上传的请求头部.可选值:无;默认值: -;类型: object。如:headers: {authorization: 'authorization-text',},
    • <12>listType: 表示上传按钮的默认样式,这个样式改变了之后,上传按钮下面的上传列表的样式也会改变.可选值:text, picture 和 picture-card;默认值: ‘text’;类型: string。
      • text: 按钮默认样式就为字符串,样式就为Upload组件里面包含的东西。上传按钮下面的上传列表,上传列表就为一个普通的list,里面是文字
      • picture: 按钮默认样式就为字符串,样式就为Upload组件里面包含的东西。上传按钮下面的上传列表,上传列表也是一个list,不过这个list里面就不是文字了而是对应图片的预览图
      • picture-card: 按钮默认样式就为一个框框,框框里面就为Upload组件里面包含的东西。上传按钮下面的上传列表,上传列表也是一个list,不过这个list里面就不是文字了而是对应图片的预览图
    • <13>multiple: 表示是否支持多选文件,开启后按住 ctrl 可选择多个文件.可选值:无;默认值: false;类型: boolean
    • <14>name: 表示上传到后台的FormData里面的参数名字,值为二进制的文件。.可选值:无;默认值: ‘file’;类型: string。
    • <15>previewFile: 表示自定义文件预览逻辑,用于处理非图片格式文件(例如视频文件).可选值:无;默认值: -;类型: (file: File | Blob) => Promise<dataURL: string>。
    • <16>showUploadList: 表示是否展示上传文件之后,fileList对应的上传文件列表(设置为false则不显示列表,就可以自定义列表了,可以配合customRequest使用)。以及文件上面的那些预览、删除、下载按钮。 可设为一个对象,用于单独设定 showPreviewIcon, showRemoveIcon 和 showDownloadIcon.可选值:无;默认值: true;类型: Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean }。
      • showUploadList: {showPreviewIcon: true,showRemoveIcon: true,showDownloadIcon: false},表示在上传的文件里面显示,预览按钮、删除按钮,不显示下载按钮
    • <17>supportServerRender: 表示服务端渲染时需要打开这个.可选值:无;默认值: false;类型: boolean。
    • <18>withCredentials: 表示上传请求时是否携带 cookie.可选值:无;默认值: false;类型: boolean
    • <19>openFileDialogOnClick: 表示点击打开文件对话框.可选值:无;默认值: true;类型: boolean。
    • <20>transformFile: 表示在上传之前转换文件(例如添加水印)。支持返回一个 Promise 对象.可选值:无;默认值: -;类型: Function(file): string | Blob | File | Promise<string | Blob | File>。
      • 这个实际的操作方法是读取需要上传的文件,reader成一个dataURL,赋值为一个img,然后用canvas给图片画一个水印上。
// 用beforeUpload的方式进行上传
  // 附件,文件上传
  const attachmentFileUpload = (file) => {
    const { uid, size } = file;
    if (size > 2097152) {message.warning('11');return false;}
    const tempFileList = JSON.parse(JSON.stringify(attachmentFileList));
      window.gSocketor = new WebSocketor({
        onopened: () => {window.gSocketor.setUploadData({file,});},
        onuploadFinished: result => {
          // 上传成功之后,把对应的图片url,放到对应的数组里面去。这里下面这个复制,必须要深复制。如果是浅复制的话要报错。
          const { file_name, file_url, file_md5, file_type } = result;
          tempFileList.push({
            uid,
            name: file_name,
            status: 'done',
            url: file_url,
          });
          setAttachmentFileList(tempFileList);
        },
      });
    return false;
  };

  // 附件,删除
  const removeAttachment = (file) => {
    const { uid } = file;
    const tempFileList = JSON.parse(JSON.stringify(attachmentFileList));
    const index = tempFileList.findIndex(value => value.uid === uid);
    tempFileList.splice(index,1);
    setAttachmentFileList(tempFileList);
  };

<Upload accept='.png' 
    listType='text' 
    multiple 
    beforeUpload={file => {attachmentFileUpload(file)}} 
    onRemove={(file)=>{removeAttachment(file)}} 
    fileList={attachmentFileList}
/>


// 直接用原生的action方式进行上传

// 这下面为上传附件框的样式
.uploadBox {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100px;
  height: 100px;
  background: #fafafa;
  border: 1px dashed #d9d9d9;
  border-radius: 4px;
  margin-bottom: 8px;
  transition: border-color 0.3s ease;
  cursor: pointer;
  &:hover {border-color: #1890ff;}
}

// 这个是上传附件的图片
.attachmentPicBox {
  // 最外层的box
  float: left; // 这里设置左浮动,由于浮动的特性,会让后面的div渲染在浮动元素的右边。所以,后面的上传加号就在这个图片的右边了,上传加号下面的文件依然是最靠近左边的
  width: 104px;
  height: 104px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  padding: 8px;
  margin: 0 8px 8px 0;
  .attachmentInner {
    // 包裹里面的所有元素,图片和阴影框
    position: relative;
    width: 100%;
    height: 100%;
    background: transparent;
    .attachmentListBox {
      // 里层的阴影和里面的按钮
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: 0.3s ease;
      background-color: rgba(0, 0, 0, 0.5);
      opacity: 0;
      &:hover {opacity: 1;}
      .attachmentListItems {
        width: 100%;
        height: 21px;
        font-size: 16px;
        color: rgba(255, 255, 255, 0.85);
      }
    }
  }
}

/*
 * 参数
 * initFileList: 默认的文件列表。类型:array。可选,默认为[]
 * disable: 是否禁用上传组件。类型:boolean。可选,默认为false..现在组件里面editUserManualType === 'detail'就是true
 * maxLength: 最大的上传数量。类型:number。可选,默认为20
 * getFileList: 当filelist改变的时候,获取filelist的函数。类型function。必选
 * isShowUploadList: 是否展示默认的上传列表。类型:boolean。可选,默认为true
 */
import React, {useState,useEffect,} from 'react';
import {Row,Col,message,Upload,Icon,} from 'antd';
import styles from './index.less';

function UploadWithProgress(props) {
  const { initFileList = [], disable = false, maxLength = 20, getFileList, isShowUploadList = true } = props;
  const [attachmentFileList, setAttachmentFileList] = useState([]); // 附件的fileList

  // 附件,删除。上面自定义的图片的删除,就调用的这个
  const removeAttachment = file => {
    const { uid } = file;
    const tempFileList = JSON.parse(JSON.stringify(attachmentFileList));
    const index = tempFileList.findIndex(value => value.uid === uid);
    tempFileList.splice(index, 1);
    setAttachmentFileList(tempFileList);
  };

  // 附件,文件上传,和删除
  const changeFileUpload = (file, fileList) => {
    const { uid, name, status, response, type, size  } = file;
    const tempFileList = JSON.parse(JSON.stringify(attachmentFileList));
    if (status === 'removed') {
      const index = tempFileList.findIndex(value => value.uid === uid);
      tempFileList.splice(index, 1);
      setAttachmentFileList(tempFileList);
      return;
    }
    if (size > 2097152) {message.warning('error');return;}
    if (status === 'done') {
      if (!response.result) {message.error('上传失败',1);return;}
      const tempIndex = tempFileList.findIndex(item => item.file_md5 === undefined); // 这句是必需的,找到之前的临时的filelist,然后用下面真实的去替换
      tempFileList.splice(tempIndex, 1, {uid,name,status,url:response.result.url,});
      setAttachmentFileList(tempFileList);
      return;
    }
    setAttachmentFileList([...fileList]);
  };

  const uploadProps = {
    name: 'uploadFile',
    action: '/ptapi/portal/uploadImg', // 这个为请求的地址
    headers: {portalsessionid: window.portalsessionid || window.localStorage.getItem('portalsessionid'),},
    accept: '.png, .jpg, .jpeg, .svg, .gif, .bmp, .psd, .eps, .dxf, .tiff, .tif, .wmf',
    listType: 'text',
    onChange: ({file, fileList})=>{changeFileUpload(file, fileList)},
    fileList: attachmentFileList,
    showUploadList: isShowUploadList,
  };

  // 附件,移动位置。 这个移动就是把左右两个交换位置就好了
  const moveAttachmentPosition = (type = 'left', index) => {
    const tempFileList = JSON.parse(JSON.stringify(attachmentFileList));
    if (index === 0 && type === 'left') {message.error('最左边的图片');return;}
    if (index === tempFileList.length - 1 && type === 'right') {message.error('最右边的图片了');return;}
    const currentItem = tempFileList[index];
    const aimIndex = type === 'left' ? index - 1 : index + 1; // 这个就是当前item,要转移去的目标位置的index
    tempFileList[index] = tempFileList[aimIndex];
    tempFileList[aimIndex] = currentItem;
    setAttachmentFileList(tempFileList);
  };

  useEffect(() => {setAttachmentFileList(initFileList);}, [initFileList]);

  // 每次attachmentFileList改变的时候,执行传入的获取值函数。获取值函数的参数,就是当前的所有文件数组。这个是重点
  useEffect(() => {getFileList(attachmentFileList);}, [attachmentFileList]);

  return (
    <div>
      {attachmentFileList.map((file, index) => {
        return (
          <div className={styles.attachmentPicBox}>
            <div className={styles.attachmentInner}>
              <img width="86" height="86" src={file.url} alt="图片.jpg" />
              {/* 里层的阴影,和阴影上面的按钮 */}
              <div className={styles.attachmentListBox}>
                <Row type="flex" justify="space-around" className={styles.attachmentListItems}>
                  <Col style={
   
   { cursor: 'pointer',}} onClick={() => {moveAttachmentPosition('left', index);}}><Icon type="caret-left" /></Col>
                  <Col style={
   
   { cursor: 'pointer' }} onClick={() => {window.open(file.url);}}><Icon type="eye" /></Col>
                  <Col style={
   
   { cursor: 'pointer',}} onClick={() => {removeAttachment(file);}}><Icon type="delete" /></Col>
                  <Col style={
   
   { cursor: 'pointer',}} onClick={() => {moveAttachmentPosition('right', index);}}><Icon type="caret-right" /></Col>
                </Row>
              </div>
            </div>
          </div>
        );
      })}
      <Upload {...uploadProps}>
        <div className={styles.uploadBox} style={
   
   {opacity: disable || attachmentFileList.length > maxLength - 1 ? 0 : 1,cursor: disable || attachmentFileList.length > maxLength - 1 ? 'default' : 'pointer',}}>
          <Icon type="plus" /><div>Upload</div>
        </div>
      </Upload>
      
         
    </div>
  );
}
export default UploadWithProgress;


  useEffect(() => { // 当下面的文件改变的时候,然后把对应的 Form 的值,改变为空或者任意值,就可以显示对应message里面东西了
    if (contentFileList.length !== 0) {
      form.setFieldsValue({contentPic: 1,});
      return;
    }
    form.setFieldsValue({contentPic: undefined,});
  }, [contentFileList]);

     <Row type='flex' justify='start'>
        <Col span={24}>
          <Form.Item label='内容图片'>
            {form.getFieldDecorator('contentPic',{
              initialValue: undefined,
              rules: [{required: true,message: '请选择图片',}],
            })(
              <Upload
                {...uploadProps}
              >
                {
                  editAddUserManualContentType === 'detail' ? null : (
                    <div>
                      <Icon type="plus" />
                      <div className="ant-upload-text">Upload</div>
                    </div>
                  )
                }
              </Upload>
            )}
          </Form.Item>
          <Row>
            <Col push={8}>
              <div style={
   
   {margin: '-35px 0px 10px'}}>支持jpg、png格式,最多支持上传1张图片</div>
            </Col>
          </Row>
        </Col>
      </Row>

Guess you like

Origin blog.csdn.net/rocktanga/article/details/121328645