移动端H5图片上传单张(拿走记得点赞,后续更新H5多张图片上传功能)

首先技术选型

首先说说为什么要是用H5自带的原生API来写这个图片上传,因为笔者在这里找了好几天。因为公司项目临时要用,时间太赶,花了一天的时间并没找到一个比较好的demo让我转接,可能实力太差。: (

序言

开发微信中我遇到图片上传请求次数问题,腾讯那边调高了借口请求次数,每天200万次。最开始只有5000,项目早上上线下午就崩了,第二天100万下载50万请求次数,还是下午5点就崩了,第三天腾讯给调到200万了。实在没有办法,不想受制于腾讯,所以只能自己去研究能上传图片的方法了。

项目思路

我们都知道H5中有canvas这个API,不知道的小伙伴可以去Google一下看看。首先我们的思路是这样的,我们先拿到图片的base64的路径,然后用canvas画布技术在画出来。然后通过canvas API 提供的方法去压缩这样图片,然后上传,一样可以达到我们想要的效果。事情就是这么简单,但是这样的坑特别的多,谁写谁写知道。

开始实现

html 部分

  # 申明一下,这里 accpet="image/*" 是为了识别出图片,所以这样写的

  

JavaScript 部分

代码中我都标注过注释了,所以就不单独在拿出来直接写了,注释已经写的相当详细了。顺带说一句,过几天会更新微信端H5图片多张上传,以下是单张。: )

  const imgInfo = {};
  function change_pic(event) {
    // 获取当前选中文件
    const file = event.target.files[0];
    // 设置图片最大尺寸
    const imgMaxSize = 1024 * 1024 * 10;
    // 检查文件类型
    if (['jpeg', 'jpg', 'png', 'gif'].indexOf(file.type.split('/')[1]) < 0) {
      // 自定义报错方式  
      console.log('图片格式不正确');
      return;
    }
    // 图片大小超过限制
    if (file.size > imgMaxSize) {
      // 自定义报错方式
      console.log('图片太大了');
      return;
    }
    // 判断是否ios
    if (!!window.navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
      // 是 ios
      insertFormData(file);
      return;
    }
    // 开始图片压缩之旅
    fileToDataUrl(file);
  }
  function insertFormData(file) {
    // 新建form对象
    const formData = new FormData();
    // 自定义form对象中的内容
    // type
    formData.append('type', file.type);
    // size 
    formData.append('size', file.size || "image/jpeg");
    // name 
    formData.append('name', file.name);
    // 最后修改时间
    formData.append('lastModifiedDate', file.lastModifiedDate);
    // 添加文件
    formData.append('file', file);
    console.log(file)
    // 上传图片
    // uploader(formData);
    fileToDataUrl(file);
  }
  function fileToDataUrl(file) {
    // 超过200k就压缩
    const imgCompressMAX_SIZE = 200 * 1024;
    // 组装相关文件数据
    imgInfo.type = file.type || "image/jpeg"; // 部分安卓机使用不了
    imgInfo.size = file.size;
    imgInfo.name = file.name;
    imgInfo.lastModifiedDate = file.lastModifiedDate;
    // 使用filereader对象的函数
    const reader = new FileReader();
    // file 转换dataURL是一个异步函数,需要写在回调函数中
    reader.onload = function (e) {
      const result = e.target.result;
      // 如果大于imgCompressMAX_SIZE 就压缩
      result.length < imgCompressMAX_SIZE ? compress(result, false) : compress(result)
    }
    reader.readAsDataURL(file);
  }
  // canvas压缩图片
  function compress(dataUrl, shouldCompress = true) {
    const img = new window.Image();
    img.src = dataUrl;
    console.log(img.src.length)
    img.onload = function () {
      // 开始绘制图片
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      // 压缩过后图片的url
      let compressedDataUrl;
      shouldCompress = true ? compressedDataUrl = canvas.toDataURL(imgInfo.type, 0.2) : compressedDataUrl = canvas.toDataURL(
        imgInfo.type, 0.2)
      console.log(compressedDataUrl);
    }
    
  }
  function uploader(formData) {
    console.log(formData)
    ajax({
      method: 'post',
      url: '',
      data: formData,
      success: function (resp) {
        console.log(resp);
      },
      async: true
    });
  }
  function createXHR() {
    if (typeof XMLHttpRequest != 'undefined') {
      return new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined') {
      var version = [
        'MSXML2.XMLHttp.6.0',
        'MSXML2.XMLHttp.3.0',
        'MSXML2.XMLHttp'
      ];
      for (let i = 0; version.length; i++) {
        try {
          return new ActiveXObject(version[i]);
        } catch (e) {
          //跳过
        }
      }
    } else {
      throw new Error('您的系统或浏览器不支持XHR对象!');
    }
  }
  //名值对转换为字符串
  function params(data) {
    let arr = [];
    for (let i in data) {
      arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(data[i]));
    }
    return arr.join('&');
  }
  // 封装ajax
  function ajax(obj) {
    let xhr = createXHR();
    obj.url = obj.url + '?rand=' + Math.random();
    obj.data = params(obj.data);
    if (obj.method === 'get') obj.url += obj.url.indexOf('?') == -1 ? '?' + obj.data : '&' + obj.data;
    if (obj.async === true) {
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          callback();
        }
      };
    }
    xhr.open(obj.method, obj.url, obj.async);
    if (obj.method === 'post') {
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      xhr.send(obj.data);
    } else {
      xhr.send(null);
    }
    if (obj.async === false) {
      callback();
    }
    function callback() {
      if (xhr.status == 200) {
        obj.success(xhr.responseText); //回调传递参数
      } else {
        console.log('获取数据错误!错误代号:' + xhr.status + ',错误信息:' + xhr.statusText);
      }
    }
  }
  // add event
  function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
      obj.addEventListener(type, fn, false);
    } else if (obj.attachEvent) {
      obj.attachEvent('on' + type, function () {
        fn.call(obj);
      });
    }
  }
  //  remove event
  function removeEvent(obj, type, fn) {
    if (obj.removeEventListener) {
      obj.removeEventListener(type, fn, false);
    } else if (obj.detachEvent) {
      obj.detachEvent('on' + type, fn);
    }
  }

PS 问题补充,上边代码只是单张上传,多张正在实现中,持续更新中!有帮助的话记得点个赞。
   没办法,我也是临时遇到这个问题,完全没有想微信上传图片请求API是有次数制的,这是我之前没有遇到的过的,今天就记录下来,以便自己之后使用。我最终的结果就是把压缩过后的base64位的代码交给后台处理就好了。这样就实现了这个功能。

你可能感兴趣的:(移动端H5图片上传单张(拿走记得点赞,后续更新H5多张图片上传功能))