# Uploader 文件上传

### 引入

在`app.json`或`index.json`中引入组件，默认为`ES6`版本

```json
"usingComponents": {
  "van-uploader": "@vant/weapp/uploader/index"
}
```


## 代码演示

### Demos

文件上传完毕后会触发`after-read`回调函数，获取到对应的文件的临时地址，然后再使用`wx.uploadFile`将图片上传到远程服务器上

```html
  <View>
        <demo-block title="基础用法" padding>

          <van-uploader
            name="1"
            fileList={ this.state.fileList1 }
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
          />


        </demo-block>

        <demo-block title="上传视频" padding>
          <van-uploader
            name="7"
            accept="video"
            fileList={ this.state.fileList7 }
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
          />
        </demo-block>

        <demo-block title="文件预览" padding>
          <van-uploader
            name="2"
            fileList={ this.state.fileList2 }
            multiple
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
          />
        </demo-block>

        <demo-block title="隐藏上传按钮" padding>
          <van-uploader
            name="2"
            fileList={ this.state.fileList2 }
            multiple
            showUpload="{{ false }}"
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
          />
        </demo-block>

        <demo-block title="上传状态" padding>
          <van-uploader
            name="8"
            fileList={ this.state.fileList8 }
            multiple
            maxCount="{{ 2 }}"
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
          />
        </demo-block>

        <demo-block title="限制上传数量" padding>
          <van-uploader
            name="3"
            fileList={ this.state.fileList3 }
            multiple
            maxCount="{{ 2 }}"
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
          />
        </demo-block>

        <demo-block title="自定义上传样式" padding>
          <van-uploader
            name="4"
            fileList={ this.state.fileList4 }
            maxCount="{{ 2 }}"
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete={(e)=>this.delete(e)}
            onClickPreview={()=>this.clickPreview()}
            use-slot="{{ true }}"
          >
            <van-button icon="photo" type="primary">上传图片</van-button>
          </van-uploader>
        </demo-block>

        <demo-block title="上传前校验" padding>
          <van-uploader
            name="5"
            fileList={ this.state.fileList5 }
            onBefore-read={(e)=>this.beforeRead(e)}
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete="delete"
            onClickPreview={()=>this.clickPreview()}
            use-before-read="{{ true }}"
          />
        </demo-block>

        <demo-block title="云存储上传" padding>
          <van-uploader
            name="6"
            fileList={ this.state.fileList6 }
            onBefore-read={(e)=>this.beforeRead(e)}
            onAfter-read={(e)=>this.afterRead(e)}
            onDelete="delete"
            onClickPreview={()=>this.clickPreview()}
            use-before-read="{{ true }}"
          />
          <view className="demo-margin-bottom">
            <van-button type="primary" onClick="uploadToCloud">上传至云存储</van-button>
          </view>
        </demo-block>

      </View>
```

```js
class UploaderComponents extends Component {
  constructor(props) {
    super(props)
  };

  state = {
    fileList1: [],
    fileList2: [
      { url: 'https://goss.veer.com/creative/vcg/veer/800water/veer-149048762.jpg' },
      { url: 'https://goss.veer.com/creative/vcg/veer/800water/veer-315358857.jpg' }
    ],
    fileList3: [{ url: 'https://goss.veer.com/creative/vcg/veer/800water/veer-141542994.jpg' }],
    fileList4: [],
    fileList5: [],
    fileList6: [],
    cloudPath: [],
    fileList7: [],
    fileList8: [
      {
        url: 'https://goss.veer.com/creative/vcg/veer/800water/veer-149048762.jpg',
        status: 'uploading',
        message: '上传中'
      },
      {
        url: 'https://goss.veer.com/creative/vcg/veer/800water/veer-315358857.jpg',
        status: 'failed',
        message: '上传失败'
      }
    ]
  };

  componentWillMount() {

  }

  //onShow
  componentDidShow() {

  }

  beforeRead(event) {
    const { file, callback = () => {} } = event.detail;
    if (file.path.indexOf('jpeg') < 0) {
      wx.showToast({ title: '请选择jpeg图片上传', icon: 'none' });
      callback(false);
      return;
    }
    callback(true);
  }

  afterRead(event) {
    const { file, name } = event.detail;
    const fileList = this.state[`fileList${name}`];
    this.setState({ [`fileList${name}`]: fileList.concat(file) });
  }

  oversize() {
    wx.showToast({ title: '文件超出大小限制', icon: 'none' });
  }

  delete(event) {
    const { index, name } = event.detail;
    const fileList = this.state[`fileList${name}`];
    fileList.splice(index, 1);
    this.setState({ [`fileList${name}`]: fileList });
  }

  clickPreview() {}

  uploadToCloud() {
    wx.cloud.init();
    const { fileList6: fileList = [] } = this.state;
    if (!fileList.length) {
      wx.showToast({ title: '请选择图片', icon: 'none' });
    } else {
      const uploadTasks = fileList.map((file, index) =>
        this.uploadFilePromise(`my-photo${index}.png`, file)
      );
      Promise.all(uploadTasks)
        .then(data => {
          wx.showToast({ title: '上传成功', icon: 'none' });
          const fileList = data.map(item => ({ url: item.fileID }));
          this.setState({ cloudPath: data, fileList6: fileList });
        })
        .catch(e => {
          wx.showToast({ title: '上传失败', icon: 'none' });
          console.log(e);
        });
    }
  }

  uploadFilePromise(fileName, chooseResult) {
    return wx.cloud.uploadFile({
      cloudPath: fileName,
      filePath: chooseResult.path
    });
  }

}
```

## API
### 注:属性应用在组件上需要统一使用驼峰式命名，如custom-class应变为
```html
<van-button type="primary" customClass='myClass' size="large">大号按钮</van-button>
```
### 注:事件应用在组件上需要统一使用驼峰式命名，如bind:click/bind:search/bind:before-enter应变为
```html
<van-button type="primary" onClick={()=>this.onClick()}>大号按钮</van-button>
<van-search type="primary" onSearch={()=>this.onSearch()}>大号按钮</van-search>
<van-transition type="primary" onBeforeEnter={()=>this.onBeforeEnter()}>大号按钮</van-transition>
```
### Props

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| name | 标识符，可以在回调函数的第二项参数中获取 | _string \| number_ | - |
| accept | 接受的文件类型, 可选值为`all` `media` `image` `file` `video` | _string_ | `image` |
| sizeType | 所选的图片的尺寸, 当`accept`为`image`类型时设置所选图片的尺寸可选值为`original` `compressed` | _string[]_ | `['original','compressed']` |
| preview-size | 预览图和上传区域的尺寸，默认单位为`px` | _string \| number_ | `80px` |
| preview-image | 是否在上传完成后展示预览图 | _boolean_ | `true` |
| preview-full-image | 是否在点击预览图后展示全屏图片预览 | _boolean_ | `true` |
| multiple | 是否开启图片多选，部分安卓机型不支持 | _boolean_ | `false` |
| disabled | 是否禁用文件上传 | _boolean_ | `false` |
| show-upload | 是否展示文件上传按钮 | _boolean_ | `true` |
| deletable | 是否展示删除按钮 | _boolean_ | `true` |
| capture | 图片或者视频选取模式，当`accept`为`image`类型时设置`capture`可选值为`camera`可以直接调起摄像头 | _string \| string[]_ | `['album', 'camera']` |
| max-size | 文件大小限制，单位为`byte` | _number_ | - |
| max-count | 文件上传数量限制 | _number_ | - |
| upload-text | 上传区域文字提示 | _string_ | - |
| image-fit | 预览图裁剪模式，可选值参考小程序`image`组件的`mode`属性 | _string_ | `scaleToFill` |
| use-before-read | 是否开启文件读取前事件 | _boolean_ | - |
| camera | 当 accept 为 `video` 时生效，可选值为 `back` `front` | _string_ | - |
| compressed | 当 accept 为 `video` 时生效，是否压缩视频，默认为`true` | _boolean_ | - |
| max-duration | 当 accept 为 `video` 时生效，拍摄视频最长拍摄时间，单位秒 | _number_ | - |
| upload-icon | 上传区域图标，可选值见 [Icon 组件](#/icon) | _string_ | `plus` |

#### accept 的合法值

| 参数    | 说明                           |
| ------- | ------------------------------ |
| `media` | 图片和视频                     |
| `image` | 图片                           |
| `video` | 视频                           |
| `file`  | 除了图片和视频之外的其它的文件 |
| `all`   | 所有文件                       |

### Slot

| 名称 | 说明           |
| ---- | -------------- |
| -    | 自定义上传区域 |

### Event

| 事件名 | 说明 | 回调参数 |
| --- | --- | --- |
| bind:before-read | 文件读取前，在回调函数中返回 `false` 可终止文件读取，绑定事件的同时需要将`use-before-read`属性设置为`true` | `event.detail.file`: 当前读取的文件，`event.detail.callback`: 回调函数，调用`callback(false)`终止文件读取 |
| bind:after-read | 文件读取完成后 | `event.detail.file`: 当前读取的文件 |
| bind:oversize | 文件超出大小限制 | - |
| bind:click-preview | 点击预览图片 | `event.detail.index`: 点击图片的序号值 |
| bind:delete | 删除图片 | `event.detail.index`: 删除图片的序号值 |
