基于Taro框架的微信小程序视频上传组件的封装

344 阅读2分钟

参与的微信小程序项目需要一个上传视频的功能,最开始的想法是从与Taro框架搭配的Taro UI库中寻找一个视频上传组件,但是在浏览了Taro UI库后,只发现了ImagePicker 图片选择器,所以决定自己封装一个视频上传组件VideoUpLoad。
话不多说,直接上代码:
index.js

class VideoUpLoad extends Component {
  constructor(props) {
    super(props);
    this.state = {
      src: [], //视频url
      srcList: [], //视频的fileName
    };
  }

  chooseVideo =() => { //视频上传,并判断最大数量
    const { type, onChange, checkLoading} = this.props;
    const {src} = this.state;
    if(src.length >= 5) {
      Taro.showToast({
        title: '上传数量已达最高',
        duration: 2000,
        icon: 'error',
        mask: false,
      })
      return;
    }
    var _this = this;
    Taro.chooseVideo({
      count: 1,
      mediaType: ['video'],
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        Taro.showLoading({
          title:'视频上传中'
        })
        Taro.uploadFile({
          url: `${baseUrl}/admin/sys-file/upload?type=${type}`,
          filePath :res.tempFilePath,
          name: 'file',
          fileType: "mp4",
          header: {
            'content-type': 'multipart/form-data',
            'Authorization': tokenHandler.getSessionByKey("authorization") //存在Storage里的token
          },
          formData: {
            type: type,
          },
          complete:(response) => {
            Taro.hideLoading()
            const data = JSON.parse(response.data);
            const tempFilePathsMp3 = _this.state.src;
            const mp3List = _this.state.srcList;
            tempFilePathsMp3.push(res.tempFilePath);
            mp3List.push(data.data.fileName);
            onChange(mp3List)
            Taro.showToast({
              title: '上传成功',
              duration: 2000,
              icon: 'success',
              mask: false,
            })
            _this.setState({
              src: tempFilePathsMp3,
              srcList: mp3List
            })
          }
        })
      }
    })
  };

  deleteVideo =(index) => { //删除上传了的视频
    const { checkLoading, onChange} = this.props;
    const _this = this;
    const srcs = _this.state.src;
    const srcList = _this.state.srcList;
    const removeName = srcList[index];
    wx.showModal({
      title: '提示',
      content: '确认要删除该视频吗?',
      success: function (res) {
        if (res.confirm) {
          if(typeof checkLoading === 'function') checkLoading(true)
          Taro.request({
            url: `${baseUrl}/admin/sys-file/del?fileName=${removeName}`, // 请求的URL
            method: 'DELETE', // 请求方法为DELETE
            header: {
              'Authorization': tokenHandler.getSessionByKey("authorization"),
              "Content-Type": "application/json",
              "Accept": "application/json"
            }, // 请求头
            success(res) {
              Taro.showToast({
                title: '删除成功',
                duration: 2000,
                icon: 'success',
                mask: false,
              })
              srcs.splice(index, 1);
              srcList.splice(index, 1);
              onChange(srcList);
              _this.setState({
                src: srcs
              })
            },
            fail(err) {
              // 请求失败的处理逻辑
              console.error('删除失败', err);
            }
          })
        } else if (res.cancel) {
          console.log("点击取消了");
          return false
        }
      }
    })
  }

  render() {
    const {videoList} = this.props; //父组件传过来已经上传过了的视频
    const { src } = this.state;
    const videoLists = [...videoList, ...src];

    return (
      <View className="img-list">
        {videoLists.map((item, index) => {
          return <View className="upload-video" key={index}>
            <Video src={item.url} className="img-li"></Video>
            <Image className="icon-deletes at-icon at-icon-close" onClick={() => this.deleteVideo(index)}></Image>
          </View>
        })}
        <View className='upload-div' onClick={this.chooseVideo}>
          <View className='upload-div-view'>
            <AtIcon value='upload' size='50' />
            <View style={{fontSize: '24rpx'}}>选择视频</View>
          </View>
        </View>
      </View>
    );
  }
}

index.less

/* 上传的图片 */
.img-list {
  display: flex;
  padding: 10rpx;
  flex-wrap: wrap;
}
.img-li {
  width: 150rpx;
  height: 150rpx;
  margin-right: 39rpx;
  margin-bottom: 23rpx;
}

.img-li:first-child {
  margin-right: 0;
}
.img-li image {
  width: 100%;
  height: 100%;
}
.icon-delete {
  width: 28rpx !important;
  height: 28rpx !important;
  position: relative;
  float: right;
  margin-top: -229rpx;
  margin-right: -15rpx;
  z-index: 99;
}
.icon-deletes {
  width: 50rpx !important;
  height: 50rpx !important;
  position: relative;
  float: right;
  margin-left: -36rpx;
  margin-right: 29rpx;
  z-index: 99;
  color: rgb(177, 173, 173);
  // background-color: red;
}
.content-input-z {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 24rpx;
  color: #999999;
}

.content-input-z {
  margin-top: 31rpx;
}

.content-input-z view image {
  width: 32rpx;
  height: 31rpx;
  margin-right: 11rpx;
}
.content-input-z view {
  display: flex;
  align-items: center;
}

.upload-div {
  width: 150rpx;
  height: 150rpx;
  position: relative;
  border: 1px #d6e4ef solid;
  transition: background-color 0.2s;
}

.upload-div:active {
  background-color: #bfbdbd;
}

.upload-div-view {
  position: absolute;
  top: 50%;
  left: 50%;
  text-align: center;
  transform: translate(-50%, -50%);
}

组件效果:

image.png