【Taro开发】-formData图片上传组件(六)

本文详细介绍了如何在Taro小程序中进行图片上传,包括手动拼接FormData字符串以适应小程序环境,以及创建ImgPicker组件进行图片选择和上传操作。同时,文章涵盖了网络请求封装、自定义组件的实现以及图片预览等实用功能。
摘要由CSDN通过智能技术生成

Taro小程序开发

系列文章的所有文章的目录

【Taro开发】-初始化项目(一)

【Taro开发】-路由传参及页面事件调用(二)

【Taro开发】-taro-ui(三)

【Taro开发】-带token网络请求封装(四)

【Taro开发】-自定义导航栏NavBar(五)

【Taro开发】-formData图片上传组件(六)

【Taro开发】-封装Form表单组件和表单检验(七)

【Taro开发】-tabs标签页及子组件的下拉刷新(八)

【Taro开发】-简易的checkBoxGroup组件(九)

【Taro开发】-页面生成二维码及保存到本地(十)

【Taro开发】-宣传海报,实现canvas实现圆角画布/图片拼接二维码并保存(十一)

【Taro开发】-分享给好友/朋友圈(十二)

【Taro开发】-小程序自动打包上传并生成预览二维码(十三)

【Taro开发】-全局自定义导航栏适配消息通知框位置及其他问题(十四)



前言

基于Taro的微信小程序开发,主要组件库为Taro-ui
由于小程序里没有FormData类,所以POST方法如果要传multipart/form-data就会报错,所以手动拼装FormData格式的字符串。


提示:以下是本篇文章正文内容,下面案例可供参考

一、图片上传

1. 常量定义

//常量定义
const boundary = `----WebKitFormBoundaryX2UFH67x5M0xltNB`

2. 手动拼接FormData字符串

以下是我拼装及需要的格式:
formdata

// 手动拼接FormData字符串,可自行补充修改
export function createFormData(params) {
  let result = '';
  for (let i in params) {
    result += `\r\n--${boundary}`;
    if (i === 'file') {
      result += `\r\nContent-Disposition: form-data; name="${i}"; filename="${params['fileName']}"`;
      result += `\r\nContent-Type: ${params[i]?.type}`;
      result += '\r\n';
      result += '\r\n';
    } else {
      result += `\r\nContent-Disposition: form-data; name="${i}"`;
      result += '\r\n';
      result += `\r\n${params[i]}`
    }

  }
  // 如果obj不为空,则最后一行加上boundary
  if (result) {
    result += `\r\n--${boundary}--`
  }
  return result
}

3. 接口调用

function upload(params) {
  return httpService.post(`...`, {
    data: params,
    headers: {
      contentType: `multipart/form-data;boundary=${boundary}`,
    },
  });
}

网络请求部分可参考【Taro开发】-带token网络请求封装(四)

二、ImgPicker组件

1.组件代码

/* eslint-disable no-undef */
import { Component } from "react";
import { View, Text, Image } from "@tarojs/components";
import { AtImagePicker, AtMessage, AtToast } from "taro-ui";
import Taro, { getCurrentInstance } from "@tarojs/taro";
import "./index.scss";
import service from "@/services/index";
import { createFormData } from "@/utils/util";

class ImgPicker extends Component {
  constructor() {
    super();
    this.state = {
      files: []
    };
  }

  getCaption(str, code) {//截取某字符后的字符串
  	var index = str.lastIndexOf(code);
  	str = str.substring(index + 1, str.length);
  	return str;
  }

  fileToUrl = files => {
    if (!files || !files?.length) return [];
    let temp = files.map(item => {
      return item.url;
    });
    return temp;
  };

  urlToFile = urls => {
    if (!urls || !urls?.length) return [];
    let temp = urls.map(url => {
      let item = { url };
      return item;
    });
    return temp;
  };

  componentDidMount() {
    const { files } = this.props;
    if (files) this.setState({ files: this.urlToFile(files) });
  }

  componentWillUpdate(nextProps, nextState) {
    // if (JSON.stringify(nextProps.files) !== JSON.stringify(this.props.files)) {
    //   this.setState({ files:this.urlToFile(nextProps.files)  });
    // }
  }

  onChange = async imgs => {
    const { files } = this.state;
    const { onChange } = this.props;
    if (imgs?.length > files?.length) {
      //上传图片
      let uploadUrl = await this.uploadImg(imgs[imgs?.length - 1]);
      if (uploadUrl) {
        let temp = files;
        let item = {
          url: uploadUrl,
          file: {
            path: uploadUrl
          }
        };
        temp.push(item);
        this.setState(
          (preveState, preveProps) => ({
            files: temp
          }),
          () => {
            onChange && onChange(this.fileToUrl(files));
          }
        );
      }
    } else {
      //删除图片
      this.setState({ files: imgs });
      onChange && onChange(this.fileToUrl(imgs));
    }
  };

  uploadImg = async file => {
    let res = "";
    Taro.showLoading({ title: "文件上传中..." });
    let type = getCaption(file.url, ".");
    let fileUrl = {
      uri: file.url,
      type: "image/" + (type === "jpg" ? "jpeg" : type),
      name: ""
    };
    let formData = createFormData({
      bucketName: "public",
      fileName: new Date().getTime() + "." + type,
      file: fileUrl
    });
    res = await service.upload(formData);
    Taro.hideLoading();
    if (res?.failed) {
      Taro.hideLoading();
      Taro.atMessage({
        message: `上传失败,${res?.message}`,
        type: "error"
      });
    } else {
      Taro.atMessage({
        message: `上传成功`,
        type: "success"
      });
    }
    return res;
  };

  render() {
    const { maxLength } = this.props;
    const { files } = this.state;
    return (
      <View className={"imgPicker " + this.props.className}>
        <AtImagePicker
          length={2}
          mode="aspectFill"
          {...this.props}
          multiple={false}
          count={1}//调用的后端接口不允许多选
          // count={maxLength - files?.length}
          showAddBtn={files?.length !== maxLength}
          files={files}
          onChange={e => this.onChange(e)}
          onFail={e => console.log("fail", e)}
          onImageClick={(i, file) => {//点击预览
            Taro.previewImage({
              current: file?.url,
              urls: this.fileToUrl(files)
            });
          }}
        />
      </View>
    );
  }
}

ImgPicker.defaultProps = {
  maxLength: 10,
  files: []
};

export default ImgPicker;

2.组件使用

		<ImgPicker
          maxLength={6}
          files={this.state.files}
          onChange={files => {
            this.setState({ files });
          }}
        />

其他上传方式

//其他方法如上
uploadImg = async file => {
    Taro.showLoading({ title: "文件上传中..." });
    let type = getCaption(file.url, ".");
    let fileUrl = {
      uri: file.url,
      type: "image/" + (type === "jpg" ? "jpeg" : type),
      name: ""
    };
    let formData = {
      bucketName: "public",
      fileName: getCaption(file.url, "/"),
      file: fileUrl
    };
    const uploadTask = await Taro.uploadFile({
      url: apiConfig.baseUrl + `/test/v1/files/multipart`, //仅为示例,非真实的接口地址
      filePath: file.url,
      name: "file",
      formData: formData,
      header: {
        Authorization: "Bearer " + Taro.getStorageSync("TOKEN"),
        "content-type": `multipart/form-data;charset=UTF-8;boundary=${boundary}`
      },
      success: function(result) {
        Taro.hideLoading();
        let res = result.data;
        if (res?.failed || res?.error) {
          Taro.hideLoading();
          Taro.atMessage({
            message: `上传失败,${res?.message || "未知错误"}`,
            type: "error"
          });
        } else {
          Taro.atMessage({
            message: `上传成功`,
            type: "success"
          });
        }
      }
    });
    return uploadTask.data;
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-雾里-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值