【vue】移动端通过cube-ui实现图片上传

「Pre」cube-ui的安装

POST:【vue】滴滴cube-ui 简化安装_不使用后编译加载cube-ui样式-CSDN博客

  

一、普通上传

<cube-upload

    action="//目标地址"

    :simultaneous-uploads="1"

    @files-added="filesAdded"

    style="padding-left:15px" />

  methods: {

    filesAdded(files) {

      let hasIgnore = false

      const maxSize = 1 * 1024 * 1024 // 1M

      for (let k in files) {

        const file = files[k]

        if (file.size > maxSize) {

          file.ignore = true

          hasIgnore = true

        }

      }

    hasIgnore && this.$createToast({

        type: 'warn',

        time: 1000,

        txt: 'You selected >1M files'

      }).show()

    },

}

配置 action 表示上传的 URL 地址,而 simultaneous-uploads 则表示支持的并发上传个数。

通过 files-added 事件可以实现文件过滤,设置 file.ignore = true 即可。

二、普通的压缩上传

多了一个压缩图片的属性

:process-file="processFile"

和一个压缩图片的方法:

    processFile(file, next) {

      compress(file, {

        compress: {

          width: 1600,

          height: 1600,

          quality: 1

        }

      }, next)

    },

compress方法用的是鹅厂的,下边的base64上传也要用,命名是image.js,

文件内容我放到自己github里了:

POST:https://github.com/canwhite/QCVueTest/blob/master/image%20compress/image.js

/**
 * 检查图片是否有被压扁,如果有,返回比率
 * ref to http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios
 */
function detectVerticalSquash(img) {
    // 拍照在IOS7或以下的机型会出现照片被压扁的bug
    var data;
    var ih = img.naturalHeight;
    var canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = ih;
    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0);
    try {
        data = ctx.getImageData(0, 0, 1, ih).data;
    } catch (err) {
        console.log('Cannot check verticalSquash: CORS?');
        return 1;
    }
    var sy = 0;
    var ey = ih;
    var py = ih;
    while (py > sy) {
        var alpha = data[(py - 1) * 4 + 3];
        if (alpha === 0) {
            ey = py;
        } else {
            sy = py;
        }
        py = (ey + sy) >> 1; // py = parseInt((ey + sy) / 2)
    }
    var ratio = (py / ih);
    return (ratio === 0) ? 1 : ratio;
}

/**
 * dataURI to blob, ref to https://gist.github.com/fupslot/5015897
 * @param dataURI
 */
function dataURItoBuffer(dataURI){
    var byteString = atob(dataURI.split(',')[1]);
    var buffer = new ArrayBuffer(byteString.length);
    var view = new Uint8Array(buffer);
    for (var i = 0; i < byteString.length; i++) {
        view[i] = byteString.charCodeAt(i);
    }
    return buffer;
}
function dataURItoBlob(dataURI) {
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    var buffer = dataURItoBuffer(dataURI);
    return new Blob([buffer], {type: mimeString});
}

/**
 * 获取图片的orientation
 * ref to http://stackoverflow.com/questions/7584794/accessing-jpeg-exif-rotation-data-in-javascript-on-the-client-side
 */
function getOrientation(buffer){
    var view = new DataView(buffer);
    if (view.getUint16(0, false) != 0xFFD8) return -2;
    var length = view.byteLength, offset = 2;
    while (offset < length) {
        var marker = view.getUint16(offset, false);
        offset += 2;
        if (marker == 0xFFE1) {
            if (view.getUint32(offset += 2, false) != 0x45786966) return -1;
            var little = view.getUint16(offset += 6, false) == 0x4949;
            offset += view.getUint32(offset + 4, little);
            var tags = view.getUint16(offset, little);
            offset += 2;
            for (var i = 0; i < tags; i++)
                if (view.getUint16(offset + (i * 12), little) == 0x0112)
                    return view.getUint16(offset + (i * 12) + 8, little);
        }
        else if ((marker & 0xFF00) != 0xFF00) break;
        else offset += view.getUint16(offset, false);
    }
    return -1;
}

/**
 * 修正拍照时图片的方向
 * ref to http://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin
 */
function orientationHelper(canvas, ctx, orientation) {
    const w = canvas.width, h = canvas.height;
    if(orientation > 4){
        canvas.width = h;
        canvas.height = w;
    }
    switch (orientation) {
        case 2:
            ctx.translate(w, 0);
            ctx.scale(-1, 1);
            break;
        case 3:
            ctx.translate(w, h);
            ctx.rotate(Math.PI);
            break;
        case 4:
            ctx.translate(0, h);
            ctx.scale(1, -1);
            break;
        case 5:
            ctx.rotate(0.5 * Math.PI);
            ctx.scale(1, -1);
            break;
        case 6:
            ctx.rotate(0.5 * Math.PI);
            ctx.translate(0, -h);
            break;
        case 7:
            ctx.rotate(0.5 * Math.PI);
            ctx.translate(w, -h);
            ctx.scale(-1, 1);
            break;
        case 8:
            ctx.rotate(-0.5 * Math.PI);
            ctx.translate(-w, 0);
            break;
    }
}

/**
 * 压缩图片
 */
function compress(file, options, callback) {
    const reader = new FileReader();
    reader.onload = function (evt) {
        if(options.compress === false){
            // 不启用压缩 & base64上传 的分支,不做任何处理,直接返回文件的base64编码
            file.base64 = evt.target.result;
            callback(file);
            return;
        }

        // 启用压缩的分支
        const img = new Image();
        img.onload = function () {
            const ratio = detectVerticalSquash(img);
            const orientation = getOrientation(dataURItoBuffer(img.src));
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');

            const maxW = options.compress.width;
            const maxH = options.compress.height;
            let w = img.width;
            let h = img.height;
            let dataURL;

            if(w < h && h > maxH){
                w = parseInt(maxH * img.width / img.height);
                h = maxH;
            }else if(w >= h && w > maxW){
                h = parseInt(maxW * img.height / img.width);
                w = maxW;
            }

            canvas.width = w;
            canvas.height = h;

            if(orientation > 0){
                orientationHelper(canvas, ctx, orientation);
            }
            ctx.drawImage(img, 0, 0, w, h / ratio);

            if(/image\/jpeg/.test(file.type) || /image\/jpg/.test(file.type)){
                dataURL = canvas.toDataURL('image/jpeg', options.compress.quality);
            }else{
                dataURL =  canvas.toDataURL(file.type);
            }

            if(options.type == 'file'){
                if(/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)){
                    // 压缩出错,以文件方式上传的,采用原文件上传
                    console.warn('Compress fail, dataURL is ' + dataURL + '. Next will use origin file to upload.');
                    callback(file);
                }else{
                    let blob = dataURItoBlob(dataURL);
                    blob.id = file.id;
                    blob.name = file.name;
                    blob.lastModified = file.lastModified;
                    blob.lastModifiedDate = file.lastModifiedDate;
                    callback(blob);
                }
            }else{
                if(/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)){
                    // 压缩失败,以base64上传的,直接报错不上传
                    options.onError(file, new Error('Compress fail, dataURL is ' + dataURL + '.'));
                    callback();
                }else{
                    file.base64 = dataURL;
                    callback(file);
                }
            }
        };
        img.src = evt.target.result;
    };
    reader.readAsDataURL(file);
}

export default compress;

 

项目中,我是在src里边,建了个modules文件夹放进去了/src/modules/image

引入(结合自己的组件位置):

import compress from '../modules/image'

三、压缩之后base64上传

<cube-upload

  ref="upload"

  :action="action"

  :simultaneous-uploads="1"

  :process-file="processFile"

  @file-submitted="fileSubmitted"

  style = "padding-left:15px"

   />

data(){

    return{

      action: {

        target: ‘//目标地址',

        prop: 'base64Value'

      }

    }

}

methods: {

    processFile(file, next) {

      compress(file, {

        compress: {

          width: 1600,

          height: 1600,

          quality: 1

        }

      }, next)

    },

    fileSubmitted(file) {

      file.base64Value = file.file.base64

    },

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值