使用vue多组图片上传

61 篇文章 0 订阅

本文使用原生的上传有局限性,ios手机能同时选择多张图片,而安卓手机只能一张一张上传,不能一次性选择多张。所以建议调用 微信JS SDK。

 

代码如下:

<template>
    <div class="start-work viewport">
        <div class="hd tc">
            <div class="inner-wrap">
                <div class="task-name">张三 - 幸福花园 19#404</div>
                <div class="time">2018-08-08</div>
            </div>
        </div>
        <!-- <div class="bd">
            <dl class="start-pic">
                <dt>开工照片</dt>
                <dd class="cf">
                    <div class="add-pic fl">
                        <i class="icon iconfont icon-jia"></i>
                    </div>

                    <div class="pic-item fl" v-for="(item,index) in 1" :key="index">
                        <img src="" alt="">
                    </div>
                </dd>
            </dl>
        </div> -->
        <!--收货照片-->
        <dl class="receipt-pic pub-section">
            <dt>
                <h3>收货照片 <span class="c-999">(限9张)</span></h3>
            </dt>
            <dd class="cf">
                <div class="add-pic fl" v-if="formDatas.receive_imgs.length < 9">
                    <input name="files" type="file" id="file" accept="image/*" multiple="multiple" @change="imgChange($event)" />
                    <i class="icon iconfont icon-jia"></i>
                    <label for="file"></label>
                </div>

                <div class="pic-item fl" v-for="(item,index) in formDatas.receive_imgs" :key="index">
                    <!--<span v-if="item === true">
                        <mt-spinner type="snake" class="loading-more"></mt-spinner>
                    </span>-->
                    <img :src="item" alt="">
                    <span class="delete-pic" @click="deletePic(index)">
                        <i class="icon iconfont icon-icon-test"></i>
                    </span>
                </div>
            </dd>
        </dl>
        <div class="ft">
            <!--允许开工-->
            <div class="allow-start">
                <div class="label">
                    周末是否允许开工
                </div>
                <div class="v">
                    <div class="j-radio l-txt" v-for="(type,index) in allowStartData" :key="index">
                        <label>
                            <span class="txt">{{type.label}}</span>
                            <input type="radio" name="houseType" v-model="allowStartType" :value="type.value" :checked="type.value === allowStartType ? true : false">
                            <span class="icon"></span>
                        </label>
                    </div>
                </div>
            </div>

            <div class="start-btn">
                <span class="btn" @click="strtWorkFn">
                    开工
                </span>
            </div>
        </div>
    </div>
</template>

<script>
import Vue from 'vue'
import { Toast, Spinner} from 'mint-ui'
import Oss from '@/assets/js/util/aliyunOss.js'
Vue.component(Spinner.name, Spinner)
export default {
    data () {
        return {
            allowStartType: '1',
            allowStartData: [
                {
                    label: '允许',
                    value: '1'
                },
                {
                    label: '不允许',
                    value: '2'
                }
            ],
            sign: {
                accessid: '',
                dir: '',
                expire: '',
                host: '',
                policy: '',
                signature: ''
            },
            formDatas: {
                purchase_id: '',
                receive_imgs: [],
                products: [],
                remark: ''
            }
        }
    },
    created () {
    },
    mounted () {
        let _this = this
        Oss.getSign(200).then((res) => { // 获取签名
            _this.sign = res.data
            console.log(_this.sign)
            // console.log('this.sign', _this.sign)
        }).catch((err) => {
            console.log('err', err)
        })
    },
    methods: {
        apiUploadOss (ossData) {
            let _this = this
            // this.$http({
            //     url: this.sign.host,
            //     method: 'post',
            //     data: ossData,
            //     onUploadProgress (progressEvent) { // 原生获取上传进度的事件
            //         if (progressEvent.lengthComputable) {
            //             console.log(progressEvent)
            //             console.log('百分比', (progressEvent.loaded / progressEvent.total) * 100)
            //         }
            //     }
            // }).then(function (res) {
            //     _this.formDatas.receive_imgs.push(_this.sign.host + '/' + ossData.get('key'))
            //     console.log('路劲:', _this.sign.host + '/' + ossData.get('key'))
            // }).catch(function (err) {
            //     console.log(err)
            // })
            this.$http.post(_this.sign.host, ossData).then(function (res) {
                _this.formDatas.receive_imgs.push(_this.sign.host + '/' + ossData.get('key'))
                console.log('路劲:', _this.sign.host + '/' + ossData.get('key'))
            }).catch(function (err) {
                console.log(err)
            })
        },
        imgChange (e) {
            console.log('初次点击')
            let _this = this
            let files = e.target.files
            console.log(files)
            // 验证数量
            if ((this.formDatas.receive_imgs.length + files.length) > 9) {
                Toast('最多只能上传9张图片')
                return
            }

            // 验证格式
            for (let i = 0; i < files.length; i++) {
                if (!/.(jpg|jpeg|png)$/.test(e.target.files[i].name)) {
                    Toast('文件必须是jpeg,jpg,png中的一种')
                    return
                }
                // else {
                //     this.formDatas.receive_imgs.push(true) // 表示加载中
                // }
            }

            for (let i = 0; i < files.length; i++) {
                let file = e.target.files[i] // 获取图片资源
                let filename = file.name

                // 获取最终需要上传的参数
                let ossData = Oss.getFormDataParams(_this.sign, filename)

                // 添加文件
                let reader = new FileReader()
                let oImg = new Image()
                let uploadInfo = {}
                console.log('ossData', ossData)

                reader.onload = function (e) {
                    uploadInfo.imageBase64 = e.target.result
                    let src = uploadInfo.imageBase64
                    // $('#thumbnail-list').append("1->:"+getSizeByBase64(uploadInfo.imageBase64))

                    oImg.onload = function () {
                        src = Oss.compress(oImg, 0.8)
                        // 添加最后需要的参数
                        ossData.append('file', Oss.convertBase64UrlToBlob(src), filename)
                        // 开始上传
                        _this.apiUploadOss(ossData)
                    }
                    oImg.src = src
                    return true
                }
                reader.readAsDataURL(file)
            }
        },
        deletePic (index) {
            this.formDatas.receive_imgs.splice(index, 1)
            console.log(this.formDatas.receive_imgs)
        },
        strtWorkFn () {
            let _this = this
            let work_on_weekend = '1'
            if (this.allowStartType === '1') {
                work_on_weekend = true
            } else if (this.allowStartType === '2') {
                work_on_weekend = false
            }
            this.$http.post('/api/steward/projects/' + _this.$route.query.contract_id + '/start', {contract_id: _this.$route.query.contract_id, work_on_weekend: work_on_weekend, work_images: _this.formDatas.receive_imgs}).then((res) => {
                let datas = res.data
                if (datas.code === 0) {
                    console.log(datas)
                } else {
                    Toast({
                        message: datas.msg,
                        duration: 2000
                    })
                }
            })
        }
    }
}
</script>

<style lang="less" scoped >
    @import (reference) "~less/base.less";
    .start-work{
        font-size:.28rem;
        .hd{
            background:#fff;
            padding-left:.38rem;
            .inner-wrap{
                padding:.5rem .38rem .2rem 0;
            }
        }
        // 收货图片
        .receipt-pic{
            padding: 0.5rem 0 0 0.4rem;
            border-bottom:.1rem solid @c-f5;
            h3{
                border-bottom:1px solid @c-border;
                padding-bottom: 0.2rem;
                span{
                    font-size:.14rem;
                    color: @c-999;
                }
            }
            dd {
                padding:.44rem 0 .6rem;
                .add-pic {
                    position:relative;
                    border: 2px dashed @c-999;
                    width: 1.34rem;
                    height: 1.34rem;
                    float: left;
                    text-align: center;
                    margin-right:.2rem;
                    box-sizing: border-box;
                    .icon-jia{
                        font-size:.54rem;
                        color:@c-999;

                        line-height:1.32rem;
                    }

                    label{
                        position:absolute;
                        top:0;
                        left:0;
                        z-index:1;
                        width:100%;
                        height:100%;
                    }

                    input{
                        width: 0.1px;
                        height: 0.1px;
                        opacity: 0;
                        overflow: hidden;
                        position: absolute;
                        z-index: -1;
                    }
                }
                .pic-item {
                    position:relative;
                    width: 1.34rem;
                    height: 1.34rem;
                    margin:0 .2rem .2rem 0;
                    img {
                        width: 100%;
                        height: 100%;
                    }
                    .delete-pic{
                        position:absolute;
                        top:-.15rem;
                        right:-.15rem;
                        background:@c-high;
                        border-radius: 50%;
                        z-index:1;
                        width:.38rem;
                        height:.38rem;
                        text-align: center;
                        line-height:.38rem;
                        .tc;
                    }
                    .icon-icon-test{
                        font-size:.12rem;
                        color:#fff;
                        display:inline-block;
                        transform: scale(0.8,0.8);
                    }
                }
            }
        }

        .ft{
            background:#fff;
            padding:.4rem .38rem .88rem;

            .allow-start{
                .display-flex;
                line-height:.4rem;

                .v{
                    flex: 1;
                    .tr;
                }

                .j-radio:last-child{
                    margin-left:.4rem;
                }
            }

            .start-btn{
                margin-top:2.5rem;
            }
            .btn{
                .btn-main(100%,1rem,.28rem, 5px);
                background:@c-main;
                color:#fff;
            }
        }
    }
</style>

aliyunOss.js文件,需要获取后台签名。

import Axios from 'axios'
export default {
    getSign (module) {
        return new Promise(function (resolve, reject) {
            // Axios.post('http://test.enlife.jjcclife.com/api/user/upload/sign?token=e1411e831c3a054610427bca05385583', {
            Axios.post('/api/images/sign', {
                module: module
            }).then(function (res) {
                let datas = res.data
                if (datas.code === SUCCESS_CODE) {
                    resolve(datas)
                } else {
                    reject(datas)
                }
            }).catch(function (err) {
                reject(err)
            })
        })
    },
    randomString (len) {
        len = len || 32
        let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
        let maxPos = chars.length
        let pwd = ''
        for (let i = 0; i < len; i++) {
            pwd += chars.charAt(Math.floor(Math.random() * maxPos))
        }
        return pwd
    },
    convertBase64UrlToBlob (urlData) {
        let bytes = window.atob(urlData.split(',')[1]) // 去掉url的头,并转换为byte

        // 处理异常,将ascii码小于0的转换为大于0
        let ab = new ArrayBuffer(bytes.length)
        let ia = new Uint8Array(ab)
        let mimeString = urlData.split(',')[0].split(':')[1].split(';')[0]
        for (let i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i)
        }

        return new Blob([ab], {type: mimeString})
    },
    getFormDataParams (sign, fileName) {
        // 构造formdata表单数据
        let ossData = new FormData()
        // let key = sign.dir + '/' + this.randomString() + '.' + fileName.split('.')[1]
        let key = ''
        if (/\/$/.test(sign.dir)) {
            key = sign.dir + this.randomString() + '.' + fileName.split('.')[1]
        } else {
            key = sign.dir + '/' + this.randomString() + '.' + fileName.split('.')[1]
        }
        console.log('key', key)
        ossData.append('OSSAccessKeyId', sign.accessid)
        ossData.append('policy', sign.policy)
        ossData.append('Signature', sign.signature)
        ossData.append('success_action_status', 200)
        ossData.append('key', key)

        return ossData
    },
    compress (img, quality) {
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')

        // 瓦片canvas
        let tCanvas = document.createElement('canvas')
        let tctx = tCanvas.getContext('2d')

        // let maxSize = 200 * 1024 // 200KB
        quality = quality || 0.8 // 图片压缩质量

        let initSize = img.src.length
        let width = img.width
        let height = img.height
        // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
        let ratio
        if ((ratio = width * height / 4000000) > 1) {
            ratio = Math.sqrt(ratio)
            width /= ratio
            height /= ratio
        } else {
            ratio = 1
        }
        canvas.width = width
        canvas.height = height
        //  铺底色
        ctx.fillStyle = '#fff'
        ctx.fillRect(0, 0, canvas.width, canvas.height)
        // 如果图片像素大于100万则使用瓦片绘制
        let count
        if ((count = width * height / 1000000) > 1) {
            count = ~~(Math.sqrt(count) + 1) // 计算要分成多少块瓦片
            //      计算每块瓦片的宽和高
            let nw = ~~(width / count)
            let nh = ~~(height / count)
            tCanvas.width = nw
            tCanvas.height = nh
            for (let i = 0; i < count; i++) {
                for (let j = 0; j < count; j++) {
                    tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh)
                    ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh)
                }
            }
        } else {
            ctx.drawImage(img, 0, 0, width, height)
        }
        // 进行最小压缩
        let ndata = canvas.toDataURL('image/jpeg', quality)

        // console.log('压缩前:' + initSize)
        // console.log('压缩后:' + ndata.length)
        // console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%')
        tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0

        // document.write(ndata);
        if (initSize > ndata.length) { // 压缩后比原来还大,就使用原图
            return ndata
        } else {
            // return img.src
            return ndata
        }
    }
}

卓越的云计算服务提供商,230万+用户正在享受阿里云"稳定,安全,低成本"的产品服务,金牌服务:免费体验,专业快速备案,7x24小时售后,服务器只选阿里云

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值