美文网首页
taro图片上传组件(单张)兼容h5和weapp

taro图片上传组件(单张)兼容h5和weapp

作者: Sune小叶子 | 来源:发表于2019-06-12 18:00 被阅读0次

    uploadfileComponent

    // 上传佐证组件代码
    import Taro, { Component } from '@tarojs/taro'
    import { connect } from '@tarojs/redux'
    
    import { View, Input, Image, Text } from '@tarojs/components'
    import { AtIcon, AtProgress } from 'taro-ui'
    import _ from 'lodash'
    
    import PropTypes from 'prop-types'
    import { getUploadProofUrl } from '../../utils/utils'
    
    import './index.scss'
    
    @connect(({ loading }) => ({
      loading: loading.effects['global/uploadProof']
    }))
    export default class GtUploadFile extends Component {
      static propTypes = {
        existingFiles: PropTypes.array,//已经存在的文件
        uploadFileType: PropTypes.string,//上传文件类型控制,通过uploadFileType控制多个类型以逗号隔开,示例:uploadFileType:"image/gif,image/jp2"
        maxCount: PropTypes.number,//最大上传图片数
        multiple: PropTypes.bool,//是否支持多选
        onUploadFile: PropTypes.func, // 点击上传按钮时触发的事件
        onConfirom: PropTypes.func, // 点击删除按钮时触发的事件
        onRemoveImage: PropTypes.func, // 点击删除按钮时触发的事件
        tempFile: PropTypes.bool,//是文件为true 图片为false
        recTypeId: PropTypes.number,
        recId: PropTypes.number,
        subRecTypeId: PropTypes.number,
        subRecId: PropTypes.number,
      }
      static defaultProps = {
        existingFiles: [],
        uploadFileType: 'image/*',
        maxCount: 1, //最大上传图片数
        multiple: true, //是否支持多选
        onUploadFile: null, //获取上传的
        onConfirom: null, //获取删除的
        onRemoveImage: null, //删除上传的
        tempFile: false,
        recTypeId: 0,
        recId: 0,
        subRecTypeId: 0,
        subRecId: 0,
    
      }
      constructor(props) {
        super(props)
        this.state = {
          uploadTypeIsImage: true,//上传文件类型是否是上传图片
          viewFilesData: [],//图片文件,在view上面显示
          showFileProgress: false,//是否显示文件上传进度条
          fileProgress: 0,//文件上传进度条进度
          hiddenUploadBtn: false,//隐藏上传按钮
          isRemovFile: false
        }
      }
      componentWillMount() {
        const { uploadFileType } = this.props
        let uploadType = _.startsWith('image/*', uploadFileType, 0)
        if (uploadType) {
          this.setState({
            uploadTypeIsImage: true
          })
        } else {
          this.setState({
            uploadTypeIsImage: false
          })
        }
      }
      componentWillReceiveProps(nextProps) {
        //如果值是异步获取
        const { existingFiles } = nextProps
        const { viewFilesData, isRemovFile } = this.state
        if (!viewFilesData.length && !isRemovFile) {
          this.setState({
            viewFilesData: existingFiles,
            hiddenUploadBtn: true//隐藏上传按钮
          })
        } else {
          return
        }
      }
    
      //确定
      handConfirm() {
        this.props.onConfirom()
      }
    
      //获取服务器和本地用户的信息
      getIncidentalInfo() {
        const rootUrl = getUploadProofUrl('/file/upload') // 服务器地址
        const token = Taro.getStorageSync('token')  // 图片上传需要单独写入token
        const locale = Taro.getStorageSync('locale')  // 图片上传需要单独写入token
        const userLoginName = Taro.getStorageSync('userLoginName')  // 图片上传需要单独写入token
        return {
          rootUrl, token, locale, userLoginName
        }
      }
    
      //触发选择文件的事件
      handChooesFile() {
        if (process.env.TARO_ENV === 'weapp') {
          //微信环境下触发微信小程序原生API的事件
          const { uploadTypeIsImage } = this.state
          if (uploadTypeIsImage) {
            this.weappHandUpFiles()
          } else {
            this.uploadMessageFile()
          }
        } else if (process.env.TARO_ENV === 'h5') {
          //h5环境下直接触发input框的点击事件
          let uploadInput = document.getElementById('uploadInput')
          uploadInput.click();
          //点击以后会触发input框上面的onChange事件
        }
      }
      /** -----h5端的处理----- */
      //input框的onChange事件
      handSelectFiles(e) {
        let files = e.target.files
        this.handUploadFilesFun(files)
      }
      //文件循环遍历处理
      handUploadFilesFun(files) {
        let that = this
        const { uploadTypeIsImage } = this.state
        let tipsText = uploadTypeIsImage ? '张图片' : '个文件'
        let fileNamesData = []
        let imagesSrcData = [] //转化为blob格式在浏览器上显示缓存的图片
        let uploadfilemaxsize = 10 * 1024 * 1024 //大小的上限
        let uploadData = [] //确定按钮时获取的值
        if (!files.length) {
          return
        } else {
          for (let index = 0; index < files.length; index++) {
            let filesItem = files[index]
            if (filesItem.size > uploadfilemaxsize) {
              let uploadfilemsg = '上传文件大小超过系统规定上限(10M),请重新选择图片'
              Taro.showToast({ title: uploadfilemsg, icon: 'success', duration: 2000 })
              return
            } else {
    
              this.uploadFileItem(filesItem, index, (data) => {
                if (!data) {
                  return
                } else {
                  if (data.success) {
                    if (uploadTypeIsImage) {
                      //上传图片就添加URL
                      let filesSrcItem = URL.createObjectURL(filesItem);
                      imagesSrcData.push(filesSrcItem)
                    } else {
                      //上传文件就添加filename
                      let fileName = filesItem.name
                      fileNamesData.push(fileName)
                    }
                    let showViewFilesData = uploadTypeIsImage ? imagesSrcData : fileNamesData
                    that.setState({
                      viewFilesData: showViewFilesData
                    });
                    Taro.showToast({ title: `第${index + 1}${tipsText}上传成功`, icon: 'success', duration: 2000 })
                    uploadData.push(data.data[0])
                    if (index === files.length - 1) {
                      that.props.onUploadFile(uploadData)
                      return
                    }
                  } else {
                    Taro.showToast({ title: `第${index + 1}${tipsText}上传失败`, icon: 'error', duration: 2000 })
                    that.setState({
                      hiddenUploadBtn: false
                    })
                    console.log(data, 'error')
                    return
                  }
    
                }
              })
            }
          }
    
        }
    
      }
      //单个文件(图片)上传服务器
      uploadFileItem(filesItem, index, callback) {
        let that = this
        const { rootUrl, token, locale, userLoginName } = this.getIncidentalInfo()
        const { maxCount, tempFile, recTypeId, recId, subRecTypeId, subRecId } = this.props
        if (index > maxCount) {
          return
        } else {
          let formData = new FormData();
          let xhr = new XMLHttpRequest();
          xhr.open('POST', rootUrl, true);  // 第三个参数为async?,异步/同步
          formData.append(filesItem.name, filesItem);
          //把请求相关参数放入formData中
          formData.append('tempFile', tempFile);
          formData.append('recTypeId', recTypeId);
          formData.append('recId', recId);
          formData.append('subRecTypeId', subRecTypeId);
          formData.append('subRecId', subRecId);
    
          xhr.setRequestHeader("userToken", token);
          xhr.setRequestHeader("userLoginName", userLoginName);
          xhr.setRequestHeader("userLanguage", locale);
    
          that.setState({
            showFileProgress: true
          })
          //监听请求的进度并在回调中传入进度参数
          xhr.upload.addEventListener('progress', (e) => {
            if (e.lengthComputable) {
              let progress = Math.round((e.loaded / e.total) * 100);
              that.setState({
                fileProgress: progress
              })
              if (progress === 100) {
                setTimeout(function () {
                  that.setState({
                    hiddenUploadBtn: true,
                    showFileProgress: false
                  })
                }, 30)
              }
            }
          }, false);  // 第三个参数为useCapture?,是否使用事件捕获/冒泡
          //监听readyState的变化,完成时回调后端返回的response
          xhr.addEventListener('readystatechange', (e) => {
            let response = e.currentTarget.response ? JSON.parse(e.currentTarget.response) : null;
            if (e.currentTarget.readyState === 4) {
              callback(response);
              xhr.upload.removeEventListener('progress', (event) => {
                if (event.lengthComputable) {
                  let progress = Math.round((event.loaded / event.total) * 100);
                  that.setState({
                    fileProgress: progress
                  })
                  if (progress === 100) {
                    that.setState({
                      showFileProgress: false
                    })
                  }
                }
              }, false)
            } else {
              console.log('upload loading ... ')
            }
          }, false);
          xhr.send(formData);
    
        }
      }
    
      /** -----weapp端的处理---- */
      //图片
      weappHandUpFiles() {
        let that = this
        const { maxCount, tempFile, recTypeId, recId, subRecTypeId, subRecId } = this.props
        const { rootUrl, token, locale, userLoginName } = this.getIncidentalInfo()
        let imagesSrcData = [] //在浏览器上显示缓存的图片
        let imagesUploadData = [] //确定按钮时获取的值
        Taro.chooseImage({
          count: maxCount,
          sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
          sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
          success: (res) => {
            // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
            let tempFilePaths = res.tempFilePaths
            for (let i = 0; i < tempFilePaths.length; i++) {
              if (i > maxCount) {
                return
              } else {
                let tempFileItem = tempFilePaths[i]
                imagesSrcData.push(tempFileItem)
                const uploadTask = Taro.uploadFile({
                  url: rootUrl, //里面填写你的上传图片服务器API接口的路径 
                  filePath: tempFileItem,//要上传文件资源的路径 String类型 
                  name: 'gantIbom',//按个人情况修改,文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,(后台接口规定的关于图片的请求参数)
                  header: {
                    "Content-Type": "multipart/form-data",//记得设置
                    "userToken": token,
                    "userLoginName": userLoginName,
                    "userLanguage": locale,
                  },
                  formData: {
                    //和服务器约定的token, 一般也可以放在header中
                    'tempFile': tempFile,
                    'recTypeId': recTypeId,
                    'recId': recId,
                    'subRecTypeId': subRecTypeId,
                    'subRecId': subRecId,
                  },
                  success: (data) => {
                    let result = JSON.parse(data.data)
                    if (result.success) {
    
                      Taro.showToast({ title: `第${i + 1}张图片上传成功`, icon: 'success', duration: 2000 })
                      imagesUploadData.push(result.data)
                      if (i === tempFilePaths.length - 1) {
                        this.props.onUploadFile(imagesUploadData)
                      }
                    } else {
                      Taro.showToast({ title: `第${i + 1}张图片上传失败`, icon: 'error', duration: 2000 })
                      return
                    }
                  },
                  fail: (err) => {
                    console.log(err)
                  }
                })
                uploadTask.progress((progress) => {
                  this.setState({
                    fileProgress: progress.progress
                  })
                  if (progress.progress === 100) {
                    that.setState({
                      hiddenUploadBtn: true
                    })
                    setTimeout(function () {
                      that.setState({
                        showFileProgress: false
                      })
                    }, 600)
                  }
                })
              }
            }
            this.setState({
              viewFilesData: imagesSrcData
            });
    
          },
          fail: (err) => {
            console.log(err)
          }
        })
      }
      //文件
      uploadMessageFile() {
        let that = this
        const { tempFile, recTypeId, recId, subRecTypeId, subRecId } = this.props
        const { rootUrl, token, locale, userLoginName } = this.getIncidentalInfo()
        let fileNamesData = []
        let fileUploadData = []
        Taro.chooseMessageFile({
          count: 1,
          type: 'file',
          success: (res) => {
            // 返回选定的本地文件路径列表
            let tempFiles = res.tempFiles
            for (let i = 0; i < tempFiles.length; i++) {
              if (!tempFiles.length) {
                return
              } else {
                let tempFileItem = tempFiles[i]
                let fileName = tempFileItem.name
                // let fileItemName = fileName.substring(0,fileName.lastIndexOf(".")) 
                fileNamesData.push(fileName)
                this.setState({
                  showFileProgress: true
                })
                const uploadTask = Taro.uploadFile({
                  url: rootUrl, //里面填写你的上传图片服务器API接口的路径 
                  filePath: tempFileItem.path,//要上传文件资源的路径 String类型 
                  name: 'gantIbom',//按个人情况修改,文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,(后台接口规定的关于图片的请求参数)
                  header: {
                    "Content-Type": "multipart/form-data",//记得设置
                    "userToken": token,
                    "userLoginName": userLoginName,
                    "userLanguage": locale,
                  },
                  formData: {
                    //和服务器约定的token, 一般也可以放在header中
                    'tempFile': tempFile,
                    'recTypeId': recTypeId,
                    'recId': recId,
                    'subRecTypeId': subRecTypeId,
                    'subRecId': subRecId,
                  },
                  success: (data) => {
                    let result = JSON.parse(data.data)
                    if (result.success) {
                      Taro.showToast({ title: `第${i + 1}个文件上传成功`, icon: 'success', duration: 2000 })
                      fileUploadData.push(result.data)
                      if (i === tempFiles.length) {
                        this.props.onUploadFile(fileUploadData)
                      }
                    } else {
                      Taro.showToast({ title: `第${i + 1}个文件上传失败`, icon: 'error', duration: 2000 })
                      return
                    }
                  },
                  fail: (err) => {
                    console.log(err)
                  }
                })
                uploadTask.progress((progress) => {
                  this.setState({
                    fileProgress: progress.progress
                  })
                  if (progress.progress === 100) {
                    setTimeout(function () {
                      that.setState({
                        showFileProgress: false,
                        hiddenUploadBtn: true
                      })
                    }, 30)
                  }
                })
              }
            }
            this.setState({
              viewFilesData: fileNamesData
            });
          },
          fail: (err) => {
            console.log(`文件上传失败,查看错误信息:${err}`)
          }
        })
      }
    
      //文件上传缓存以后确定选中的文件上传服务器
      handConfirmFile() {
        this.props.onConfirom()
      }
      //删除文件
      handDeleteFile() {
        this.setState({
          hiddenUploadBtn: false,
          isRemovFile: true,
          viewFilesData: []
        }, () => {
          const { viewFilesData } = this.state
          this.props.onRemoveImage(viewFilesData)
        });
      }
      render() {
        const { uploadTypeIsImage, fileProgress, viewFilesData, showFileProgress, hiddenUploadBtn } = this.state
        console.log(hiddenUploadBtn, 'hiddenUploadBtn')
        const { uploadFileType } = this.props
        let showUploadFileView = null
        let uploadIcon = uploadTypeIsImage ? 'image' : 'upload'
        let uplpadIconSize = uploadTypeIsImage ? '40' : '18'
        let fileProgressClass = showFileProgress ? 'progress show-progress' : 'progress hidden-progress'
        showUploadFileView = (
          <View className='uploadfile-content'>
            {
              viewFilesData.map(fileVal => {
                return uploadTypeIsImage ? (
                  <View className='img-item-warp'>
                    <View className='img-warp'>
                      <Image className='img-item' src={fileVal} />
                    </View>
                    <View className='conforim-img' onClick={this.handConfirmFile.bind(this)}>确认</View>
                    <View className='icon-btn-warp'>
                      <AtIcon className='icon-btn' onClick={this.handDeleteFile.bind(this)} value='close-circle' size='24' color='#6e6e6e' ></AtIcon>
                    </View>
                  </View>
                ) : (
                    <View className='file-item-warp'>
                      <AtIcon className='icon-btn' value='file-generic' size='20' color='#336633'></AtIcon>
                      <Text className='uploadfile-name'>{fileVal}</Text>
                      <AtIcon className='close-icon-btn' onClick={this.handDeleteFile.bind(this)} value='close-circle' size='12' color='#6e6e6e'></AtIcon>
                    </View>
                  )
              })
            }
          </View>
        )
        return (
          <View className='uploadfile-components'>
            {showUploadFileView}
            <View className={hiddenUploadBtn ? 'btn-warp btn-warp-hidden' : 'btn-warp btn-warp-show'}>
              <View className={uploadTypeIsImage ? 'upload-img-btn' : 'upload-file-btn'} onClick={this.handChooesFile.bind(this)}>
                <AtIcon className='upload-icon' value={uploadIcon} size={uplpadIconSize} color='#fff'></AtIcon>
              </View>
            </View>
            <View className={fileProgressClass}>
              <AtProgress percent={fileProgress} />
            </View>
            <Input className='uploadfile-ipt' type='file' name='file' id='uploadInput' accept={uploadFileType} onChange={this.handSelectFiles.bind(this)} />
          </View>
        )
      }
    
    }
    
    
    
    .uploadfile-components{
        width:100%;
        // height: 100vh;
        position: relative;
        padding: 20px;
        .progress{
            width: 94%;
            height: 42px;
            position: absolute;
            left: 3%;
            top:21px;
            z-index: 88;
        }
        .show-progress{
           display: block;
        }
        .hidden-progress{
            display: none;
        }
        .uploadfile-content{
            .img-item-warp{
                width: 100%;
                height: 100%;
                position: relative;
                overflow: hidden;
                .img-warp{
                    display: flex;
                    flex-direction: column;
                    justify-content: center;
                    overflow: hidden;
                    width: 100vw;
                    height: 100vw;
                    .img-item{
                        width: 100%;
                        height: auto;
                        min-height: 100vw;
                    }
                }
                .conforim-img{
                    width:100%;
                    height: 68px;
                    line-height: 68px;
                    font-size: 22px;
                    text-align: center;
                    background-color: #336633;
                    color: #fff;
                    border-radius: 8px;
                    margin-top: 20px;
                }
                .icon-btn-warp{
                    width: 42px;
                    height: 42px;
                    line-height: 42px;
                    position: absolute;
                    right: 8px;
                    top: 8px;
                    .icon-btn{
                        width: 42px;
                        height: 42px;
                        line-height: 42px;
                    }
                }
    
            }
            .file-item-warp{
                width: 100%;
                height: 42px;
                line-height: 42px;
                display: flex;
                flex-direction: row;
                justify-content: flex-start;
                .icon-btn{
                    height: 42px;
                    line-height: 42px;
                }
                .uploadfile-name{
                    height: 42px;
                    line-height: 42px;
                    font-size: 20px;
                    color: #336633;
                    margin-left: 22px;
                    margin-right: 130px;
                }
                .close-icon-btn{
                    flex: 1;
                    width: 42px;
                    height: 42px;
                    line-height: 42px;
                    text-align: right;
                    margin-right: 20px;                
                }
            }
        }
        .btn-warp{
            display: flex;
            flex-direction: row;
            justify-content: flex-start;
            flex-wrap: wrap;
            &.btn-warp-hidden{
                display: none;
            }
            &.btn-warp-show{
                display: block;
            }
            .upload-img-btn{
                width: 220px;
                height: 220px;
                line-height: 220px;
                text-align: center;
                position: relative;
                background-color: #336633;
                border-radius: 14px;
                overflow: hidden;
                .upload-icon{
                    width: 220px;
                    height: 220px;
                    display: block;
                    line-height: 220px;
                    font-size: 48px;
                    color: #fff;
                    text-align: center;
                    position: absolute;
                    left: 0;
                    top: 0;
                }
            }
            .upload-file-btn{
                width: 120px;
                height: 52px;
                line-height: 38px;
                text-align: center;
                position: relative;
                background-color: #336633;
                border-radius: 14px;
                overflow: hidden;
                .upload-icon{
                    display: block;
                    width: 120px;
                    height: 52px;
                    line-height: 52px;
                    font-size: 22px;
                    color: #fff;
                    text-align: center;
                    position: absolute;
                    left: 0;
                    top: 0;
                }
            }
        }
        .uploadfile-ipt{
            position: absolute;
            top: -1220px;
            left: 0;
        }
    }
    

    组件的使用

    import Taro, { Component } from '@tarojs/taro'
    import { View } from '@tarojs/components'
    import { PageView, GtUploadFile } from '@components'
    import Avatar from '../../../static/images/default_avatar.png'
    
    export default class UploadFileExample extends Component {
    
      state = {
        tempFile:true,
        recTypeId:0,
        recId:0,
        subRecTypeId:0,
        subRecId:0,
        currentFiles:['零件库名称.xsl']
      }
      onGetUpload = (files) => {
        console.log(files, `父组件获得的value值`)
      }
    
      //删除的时图片ID设置
      onRemoveImage = (data) => {
        console.log(data)
      }
    
    
      //确定按钮点击
      onConfirom = (data) => {
        console.log(data)
      }
    
      render() {
        //tempFile ,recTypeId , recId ,subRecTypeId , subRecId业务模块区分所需的参数 组件里面默认的是用来上传头像的
        const { tempFile ,recTypeId , recId ,subRecTypeId , subRecId , currentFiles } = this.state
        console.log(currentFiles,'currentFiles')
        return (
          <PageView navTitle='UploadImage组件使用示例'>
            <View style='padding:10px 0;'>
              <View style='padding:10px'>上传文件</View>
              <GtUploadFile
                tempFile={tempFile}
                recTypeId={recTypeId} 
                recId={recId}
                subRecTypeId={subRecTypeId}
                subRecId={subRecId}
                uploadFileType='*'
                onUploadFile={this.onGetUpload} //上传按钮的回调函数
                onConfirom={this.onConfirom}  //确定按钮的回调函数
                onRemoveImage={this.onRemoveImage}  //删除按钮的回调函数
                existingFiles={currentFiles}  //默认的文件反显
              ></GtUploadFile>
            </View>
          </PageView>
        )
      }
    }
    
    

    相关文章

      网友评论

          本文标题:taro图片上传组件(单张)兼容h5和weapp

          本文链接:https://www.haomeiwen.com/subject/xgesxctx.html