当前位置: 首页 > news >正文

用element的upload组件实现多图片上传和压缩

我用vuex做状态管理,七牛云做图床。

项目地址:多图片上传组件

效果展示

图片描述

项目执行流程

首先,让我们来分析一下实现多图片上传的流程:

  • 前端向后端请求用来上传图片至服务器的token
  • 后端为每张要上传的图片生成一个图片名,并用这个图片名生成token
  • 后端将图片名和token返回给前端
  • 前端拿到token以后,将图片上传至服务器
  • 上传成功以后,前端将图片名发给后端
  • 后端将图片名存入数据库

图片描述

项目实现过程

1.我们要利用element-ui的Upload组件布置界面:

//upload.vue
<el-upload
  :action= domain
  ref="upload"
  accept='image/jpeg,image/gif,image/png'
  :auto-upload="false"
  :http-request="upqiniu"
  :limit="limit"
  :multiple="multiple"
  list-type="picture-card"
  :before-upload="beforeUpload"
  :on-preview="handlePictureCardPreview"
  :on-change="handldChange"
  :on-remove="handleRemove">
  <i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
  <img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>

domain 指的是我们的上传地址,upqiniu 是我们自定义的上传方法,beforeUpload 是图片上传前执行的方法。关于该组件的其他用法可以在element的官方文档查阅:Upload 上传

2.对图片进行压缩

// upload.vue
imgQuality: 0.5, //压缩图片的质量

dataURItoBlob(dataURI, type) {
  var binary = atob(dataURI.split(',')[1]);
  var array = [];
  for(var i = 0; i < binary.length; i++) {
    array.push(binary.charCodeAt(i));
  }
  return new Blob([new Uint8Array(array)], {type: type});
},

beforeUpload(param) {
  //对图片进行压缩
  const imgSize = param.size / 1024 / 1024
  if(imgSize > 1) {
    const _this = this
    return new Promise(resolve => {
      const reader = new FileReader()
      const image = new Image()
      image.onload = (imageEvent) => {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        const width = image.width * _this.imgQuality
        const height = image.height * _this.imgQuality
        canvas.width = width;
        canvas.height = height;
        context.clearRect(0, 0, width, height);
        context.drawImage(image, 0, 0, width, height);
        const dataUrl = canvas.toDataURL(param.type);
        const blobData = _this.dataURItoBlob(dataUrl, param.type);
        resolve(blobData)
      }
      reader.onload = (e => { image.src = e.target.result; });
      reader.readAsDataURL(param);
    })
  }
}

压缩图片实现起来比较简单。就是在beforeUpload()方法里面return一个Promise,Promise里面我们把图片的长度和宽度按比例进行缩小,并把图片画到canvas上,然后把canvas转成一个blod对象。

3.前端向后端请求上传token。

//upload.vue
upqiniu(param) {
  let filetype = ''
  if (param.file.type === 'image/png') {
    filetype = 'png'
  } else {
    filetype = 'jpg'
  }
  const formdata = {
    filetype: filetype,
    param: param
  }
  this.actionGetUploadToken(formdata)        
}

// vuex/action.js
actionGetUploadToken({commit}, obj) {
  const msg = {
    filetype: obj.filetype
  }
  usersApi.getImgUploadToken(msg).then((response) => {
    if(response.stateCode === 200) {
      commit('uploadImg', {'token': response.token, 'key': response.key, 'param': obj.param})
    } 
  }, (error) => {
    console.log(`获取图片上传凭证错误:${error}`)
    commit('uploadImgError')
  })
},

4.后端生成上传token,并发给前端,我用Python实现。

filetype = data.get('filetype')
# 构建鉴权对象
q = Auth(configs.get('qiniu').get('AK'), configs.get('qiniu').get('SK'))

# 生成图片名
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
key = salt + '_' + str(int(time.time())) + '.' + filetype

# 生成上传 Token,可以指定过期时间等
token = q.upload_token(configs.get('qiniu').get('bucket_name'), key, 3600)
return Response({"stateCode": 200, "token": token, "key": key}, 200)

5.前端接收token,开始向服务器上传图片

// vuex/state.js
imgName: [], //图片名数组

// vuex/mutations.js
uploadImg(state, msg) {
  const config = {
    useCdnDomain: true,
    region: qiniu.region.z2
  }
  var putExtra = {
    fname: msg.param.file.name,
    params: {},
    mimeType: ["image/png", "image/jpeg", "image/gif"]
  };
  var observer = {
    next(res){

    },
    error(err){
      console.log(`图片上传错误信息:${err.message}`)
    }, 
    complete(res){
      console.log(`图片上传成功:${res.key}`)
      state.imgName.push(res.key)
    }
  }
  var observable = qiniu.upload(msg.param.file, msg.key, msg.token, putExtra, config)
  //上传开始
  var subscription = observable.subscribe(observer)
},

6.上传成功以后,将图片名存入数据库

// 用到upload.vue的界面
this.imgsList = this.imgName.map(key => `http://${this.qiniuaddr}/${key}`)
switch(this.imgsList.length) {
  case 4:
  this.img4 = this.imgsList[3]
  case 3:
  this.img3 = this.imgsList[2]
  case 2:
  this.img2 = this.imgsList[1]
  case 1:
  this.img1 = this.imgsList[0]
}
let obj = {
  goods_img1: this.img1,
  goods_img2:this.img2,
  goods_img3:this.img3,
  goods_img4:this.img4
}
//将信息发送给后端
this.actionPublish(obj)

相关文章:

  • oracle表空间查询
  • linux 防爆破方法
  • [转载]看我花式绕过校园网计费认证
  • 前嗅ForeSpider采集配置界面介绍
  • Weblogic发布小问题——weblogic.descriptor.DescriptorException: VALIDATION PROBLEMS WERE FOUND
  • POI生成Excel
  • 关于Yii中CGridView关联表字段的filter问题解决方法
  • 78. Subsets
  • 如何识别一个字符串是否Json格式
  • 全能App研发助手!滴滴开源DoraemonKit
  • 码农张的Bug人生 - 初来乍到
  • cesiumjs开发实践(四) 地形介绍
  • Linux的文件管理类命令
  • java android 将小数度数转换为度分秒格式
  • [译] React v16.8: 含有Hooks的版本
  • 「面试题」如何实现一个圣杯布局?
  • CSS魔法堂:Absolute Positioning就这个样
  • echarts花样作死的坑
  • Flex布局到底解决了什么问题
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • Mac转Windows的拯救指南
  • node 版本过低
  • Python实现BT种子转化为磁力链接【实战】
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • 后端_MYSQL
  • 排序算法之--选择排序
  • 前端_面试
  • 让你的分享飞起来——极光推出社会化分享组件
  • 一些css基础学习笔记
  • 终端用户监控:真实用户监控还是模拟监控?
  • 主流的CSS水平和垂直居中技术大全
  • 自定义函数
  • MyCAT水平分库
  • 如何正确理解,内页权重高于首页?
  • #每天一道面试题# 什么是MySQL的回表查询
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (3)STL算法之搜索
  • (9)目标检测_SSD的原理
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (论文阅读11/100)Fast R-CNN
  • (十)T检验-第一部分
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (转)ObjectiveC 深浅拷贝学习
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)程序员技术练级攻略
  • ***测试-HTTP方法
  • . NET自动找可写目录
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET Core 中插件式开发实现
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .Net 路由处理厉害了
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)