图片上传知识点梳理

在我们日常的项目开发中,图片上传是一个很常见的需求。一些常见的UI框架都已经集成了图片上传组件,然而有时候这些组件并不能满足我们的需求,这时候就需要自己写组件实现上传,这就需要弄懂上传的原理以及里面的知识点。本次我就通过简单的代码,为大家解析图片上传的各个知识点。

1、传统图片上传服务器

前端通过 <input type="file"/> 获取上传文件,然后通过ajax的post(设置type为multipart/form-data)上传后端,后端取到文件后保存至服务器并返回路径。

2、微信jssdk图片上传

调用微信的jssdkchooseImage选择图片,uploadImage上传图片
image.png

3、webuploader图片上传

webuploader最常用于百度ueditor编辑器图片上传。百度内置了webuploader上传插件,我们只需修改相应逻辑即可实现阿里云oss的上传

// 富文本编辑器图片上传
window.UEDITOR_CONFIG['imageUploadService'] = function (context, uploader) {
  return {
    /**
      * 触发fileQueued事件时执行
      * 当文件被加入队列以后触发,用来设置上传相关的数据 (比如: url和自定义参数)
      * @param {Object} file 当前选择的文件对象
      */
    setUploadData: function (file) {
      // 这里添加token
      getUploadToken(function (ossInfo) {
        file.ossInfo = ossInfo
        return file
      }, file)
    },
    /**
      * 触发uploadBeforeSend事件时执行
      * 在文件上传之前触发,用来添加附带参数
      * @param {Object} object 当前上传对象
      * @param {Object} data 默认的上传参数,可以扩展此对象来控制上传参数
      * @param {Object} headers 可以扩展此对象来控制上传头部
      * @returns 上传参数对象
      */
    setFormData: function (object, data, headers) {
      let ossInfo = object.file.ossInfo
      let key = ossInfo.dir + '' + randomString(10) + getSuffix(data.name)
      data.key = key
      data.policy = ossInfo.policy
      data.OSSAccessKeyId = ossInfo.OSSAccessKeyId
      data.success_action_status = 200
      data.signature = ossInfo.signature
      let imageList = context.imageList || []
      imageList.push({
        url: ossInfo.host + '/' + key
      })
      return data
    },
    /**
      * 触发startUpload事件时执行
      * 当开始上传流程时触发,用来设置Uploader配置项
      * @param {Object} uploader
      * @returns uploader
      */
    setUploaderOptions: function (uploader) {
      return uploader
    },
    /**
      * 触发uploadSuccess事件时执行
      * 当文件上传成功时触发
      * @param {Object} res 上传接口返回的response
      * @returns {Boolean} 上传接口返回的response成功状态条件 (比如: res.code == 200)
      */
    getResponseSuccess: function (res) {
      // console.log(context)
      return true
    },
    /* 指定上传接口返回的response中图片路径的字段,默认为 url */
    imageSrcField: 'url'
  }
}

4、plupload图片上传

plupload
我们公司图片上传是需要上传至阿里云oss的,这里用的较多的是plupload上传插件。

plupload的特性

  • 自适应上传方式。根据程序当前的环境会在HTML5、flash、silverlight、input这些方式中选择最优方案 ,如果支持Html5的话他会优先使用这种方式。
  • 压缩图片可以在前端进行处理
  • 大文件分片上传,分割成小片进行一个大文件的上传

plupload安装

yarn add plupload // 或者 npm install plupload --save

实例化对象

// 实例化一个plupload上传对象
let uploader = new plupload.Uploader({
  multi_selection: false, // 禁止多文件上传
  browse_button: id, // 触发文件选择对话框的按钮,为那个元素id
  url: 'http://oss-cn-hangzhou.aliyuncs.com', // 服务器端的上传页面地址
  filters: {
    mime_types: [ // 只允许上传图片
      {title: 'Image files',extensions: 'jpg,png,gif,jpeg'}
    ],
    max_file_size: '5mb', // 最大只能上传5mb的文件
    prevent_duplicates: false // 不允许选取重复文件
  },
  resize: {
    width: 320, // 压缩后宽
    height: 240, // 压缩后高
    crop: true, // 开启图片裁剪
    quality: 55, // 裁剪质量
    preserve_headers: false // 压缩后是否保留图片的元数据
  },
  init: {
    FilesAdded (up, files) {
      // 添加文件后的业务逻辑
    },
    FileUploaded: function (up, file, res) {
      // 上传完成后的业务逻辑
    },
    Error: function (up, err) {
      // 错误信息处理
    }
  }
})

图片校验

上传文件,一般都会对图片进行校验,例如文件的类型、大小、格式、尺寸等。图片校验的配置在实例化传参,如果校验发现不符会调用Error。
image.png

初始化

uploader.init() // 初始化

上传结果

getImgUrl (host, fileName) {
  let url = host + '/' + fileName
  this.$emit('getUrl', {
    url
  })
}

单个上传组件

封装成单个组件,只需要在组件内完成上传逻辑,并绑定触发上传逻辑的dom元素即可。在上传成功后向父组件$emit通信即可

<template>
  <div class="upload">
    <button class="upload-btn primary-btn"  :id="id" >
      <i class="el-icon-plus avatar-uploader-icon"></i>
    </button>
  </div>
</template>
<script>
export default {
  props: {
    id: String, // 图片id(每次调用的时候都是需要唯一的)
    size: { // 图片的尺寸
      type: String,
      default: '2048'
    }
  },
  mounted () {
    this.initPlupload(this.id)
  }
}
</script>

5 富文本编辑器集成

这里采用的富文本编辑器是国产小巧的wangeditor,这个编辑器提供了三方上传方式的集成:

  • 使用 base64 保存图片
  • 上传图片到服务器
  • 上传到七牛云存储

但是上传到阿里云oss需要我们自己研究实现。实现原理同上,wangeditor提供了图片上传按钮的dom元素,即 editor.imgMenuId,只需要把这个id绑定到之前的plupload即可实现上传

this.initPlupload(this.editor.imgMenuId)

图片上传配置方法要在编辑器配置之前调用

6 base64上传

我们之前提到的上传都是自动的,即plupload初始化提供的dom元素点击后触发上传。那么如果想手动上传文件该怎么实现呢?
plupload文档中,有addFile()这个方法,当这个方法成功调用后就会走之前的逻辑,上传也一气呵成。
下面一个示例是使用input标签手动完成上传

<input  type="file" value="请选择文件" @change="uploadImg()" ref="uploadBtn"/>

uploadImg () {
  let files = this.$refs.uploadBtn.files[0]
  this.uploader.addFile(file)
}

在实现了文件手动上传之后,在实现base64图片上传,只需要把base64转换成file即可

uploadBase64 (base64Str) {
  let file = this.getFile(base64Str, new Date().getTime() + '.png')
  this.uploader.addFile(file)
}
getFile (dataurl, filename) {
  let arr = dataurl.split(',')
  let mime = arr[0].match(/:(.*?);/)[1]
  let bstr = atob(arr[1])
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], filename, { type: mime })
}

7 react集成

初始化方式同vue一样

componentDidMount(){
  this.initPlupload(this.state.id)
}

// 获取上传结果

getImgUrl (host, fileName) {
  let url = host + '/' + fileName
  console.log(url)
  this.props.callback(url); // 子组件传给父组件
}

8 jQuery集成

集成方法大同小异,原理都差不多。绑定Dom -> 传入文件 -> 获取token -> 上传

本文所有示例源码:https://github.com/Xonlystar/upload-demo


 上一篇
webpack学习 webpack学习
前言: 什么是Webpack WebPack可以看做是__模块打包机__:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式
2018年11月21日
下一篇 
TypeScript学习(一) TypeScript学习(一)
我是从去年开始使用TypeScript的,刚开始用的时候也是因为项目使用的ts,所以也是糊里糊涂的用着,一直没系统整理学习过,所以正好借此机会,整理一下,加深理解。 一、概念 首先呢,它是跟javaScript一样属于一种脚本语言; 其次
2018年11月07日
  目录