zoukankan      html  css  js  c++  java
  • 图片上传

    <template>
        <div class="image-upload-component" :class="{multiple: multiple}">
            <input type="file" class="input-file" :disabled="disabled" :accept="accept" :multiple="multiple" ref="inputFile" @change="fileChange" />
    
            <slot name="default">
                <template v-for="(row, index) in images">
                    <div class="image-wrapper" :key="index">
                        <img :src="row.absolute" v-if="isSuccess(row.status)" />
                        <div class="failed" v-if="isError(row.status)">上传失败</div>
    
                        <div class="tools" v-if="isSuccess(row.status) || isError(row.status)">
                            <el-button type="text" size="mini" title="预览" icon="el-icon-search" v-if="isSuccess(row.status)" />
                            <el-button type="text" size="mini" title="上传" icon="el-icon-upload2" v-if="!multiple && !disabled" @click="$refs.inputFile.click()" />
                            <el-button type="text" size="mini" title="删除" icon="el-icon-delete" v-if="!disabled" @click="deleteFile(index)" />
                        </div>
    
                        <div class="loading" v-if="isWait(row.status)"><i class="el-icon-loading" /></div>
                    </div>
                </template>
            </slot>
    
            <slot name="add" v-if="addShow">
                <div :disabled="disabled" class="add-wrapper" @click="$refs.inputFile.click()">
                    <i class="el-icon-plus" />
                </div>
            </slot>
    
            <slot name="tips">
                <div class="upload-tips">
                    <span>大小不能超过1MB</span>
                    <span>图片尺寸为1:1比例</span>
                    <span>图片只能为jpeg、jpg、png格式</span>
                </div>
            </slot>
        </div>
    </template>
    
    <script>
    
        export default {
            data (){
                return {
                    UPLOAD_WAIT: 0, //等待
                    UPLOAD_ING: 1, //上传中
                    UPLOAD_SUCCESS: 2, //上传成功
                    UPLOAD_FAILED: 3, //上传失败
    
                    accept: '.jpeg,.jpg,.png',
                    accepts: ['image/jpg', 'image/jpeg', 'image/png'],
    
                    images: [], //
                };
            },
    
            props: {
    
                /**
                 * 图片列表
                 * @example @returns
                 * [{
                 *      relative: '/xxx/xxx.png',
                 *      absolute: 'https://xxx/xxx.png'
                 * }]
                 */
                value: {
                    type: Array,
                    required: true
                },
    
                // 上传保存的文件夹
                folder: {
                    type: String,
                    required: true
                },
    
                // 是否支持多选
                multiple: {
                    type: Boolean,
                    default: false
                },
    
                // 是否禁用
                disabled: {
                    type: Boolean,
                    default: false
                },
    
                // 允许上传的文件大小,单位kb
                size: {
                    type: Number,
                    default: 1024
                },
    
                // 最大允许上传个数
                limit: {
                    type: Number,
                    default: 10
                }
            },
    
            watch: {
                value (arr){
                    if( arr && arr instanceof Array && arr.length ){
                        for (let i = 0; i < arr.length; i++) {
                            let exist = this.images.find(row => row.relative == arr[i].relative);
    
                            if( !exist ) {
                                arr[i].status = 2;
                                this.recombination(arr[i]);
                            };
                        };
                    } else {
                        this.images = [];
                    };
                }
            },
    
            computed: {
                // 是否等待上传
                isWait ( status ){
                    return status => {
                        return this.UPLOAD_WAIT == status;
                    };
                },
    
                // 是否上传中
                isUping ( status ){
                    return status => {
                        return this.UPLOAD_ING == status;
                    };
                },
    
                // 是否上传成功
                isSuccess ( status ){
                    return status => {
                        return this.UPLOAD_SUCCESS === status;
                    };
                },
    
                // 是否上传失败状态
                isError ( status ){
                    return status => {
                        return this.UPLOAD_FAILED === status;
                    };
                },
    
                // 在部分情况下显示上传按钮
                addShow (){
                    let { images, multiple, limit, disabled } = this
                    ,   length = images.length;
                    if( disabled ) return false;
                    if( multiple && length < limit ) return true;
                    if( !multiple && !length ) return true;
                    return false;
                }
            },
    
            methods: {
    
                // 选择文件
                fileChange (e){
                    let pomises = []
                    ,   { files } = e.target
                    ,   fileCount = files.length //本次选择的文件数
                    ,   vacancy = this.limit - this.images.length //剩余可上传文件数
                    ,   forNumber = vacancy > fileCount ? fileCount : vacancy;
    
                    for (let i = 0; i < forNumber; i++) {
                        pomises.push(this.validateFile(files[i]));
                    };
    
                    Promise.all(pomises).then( files => {
                        for (let i = 0; i < files.length; i++) {
                            this.beginUpload(files[i]).then( file => {
                                this.recombination(file);
                                this.emitData();
                            });
                        };
                    }).catch( msg => {
                        this.$message.warning( msg );
                    }).finally(e => {
                        this.clearInput();
                    });
                },
    
                // 验证文件是否符合规范
                validateFile (file){
                    let image = new Image()
                    ,   isSize = (file.size / 1024) > this.size
                    ,   isAccept = this.accepts.includes(file.type);
    
                    return new Promise((resolve, reject) => {
                        if(!isAccept){
                            reject('只能上传 jpeg、jpg、png 格式图片');
                        };
    
                        if (isSize) {
                            reject(`图片大小不能超过${this.renderSize(this.size)}`);
                        };
    
                        image.onload = e => {
                            if((image.width / image.height) == 1){
                                resolve(file);
                            } else {
                                reject(`请上传1:1比例的图片`);
                            };
                        };
    
                        image.onerror = e => {
                            reject('图片加载失败,请重新选择');
                        };
    
                        image.src = window.URL.createObjectURL(file);
                    });
                },
    
                recombination (file){
                    this.multiple ? this.images.push(file) : (this.images = [file]);
                },
    
                beginUpload (file){
                    return new Promise((resolve, reject) => {
                        this.$alioss.upload({ file, folder: this.folder }).then(({ relative, absolute }) => {
                            resolve({ relative, absolute, status: this.UPLOAD_SUCCESS });
                        });
                    }).catch(e => {
                        resolve({ status: this.UPLOAD_FAILED });
                    });
                },
    
                // 清空文件选择器
                clearInput (){
                    this.$refs.inputFile.value = '';
                },
    
                // 删除文件
                deleteFile (index){
                    this.images.splice(index, 1);
                    this.emitData();
                },
    
                // 只提交上传成功的文件
                emitData (){
                    let data = this.images.filter(row => row.status == this.UPLOAD_SUCCESS).map( row => {
                        let { relative, absolute } = row;
                        return { relative, absolute };
                    });
    
                    this.$emit('input', data);
                    this.$emit('change', data);
                },
    
                // 格式化文件大小
                renderSize( value = null ){
                    if ( !value ) return "0B";
                    let srcsize = parseFloat(value)
                    ,   index = Math.floor(Math.log(srcsize) / Math.log(1024))
                    ,   size = srcsize / Math.pow(1024, index)
                    ,   unitArr = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
                    size = size.toFixed(0);//保留的小数位数
                    return `${size}${unitArr[index]}`;
                }
            }
        };
    </script>
    
    <style lang="scss">
        .image-upload-component{
            display: flex;
    
            .input-file{
                display: none;
            }
    
            .image-wrapper,
            .add-wrapper{
                 120px;
                height: 120px;
                display: block;
                overflow: hidden;
                border-radius: 4px;
                box-sizing: border-box;
                border: 1px solid #DCDFE6;
            }
    
            .image-wrapper{
                display: inline-flex;
                position: relative;
                align-items: center;
                justify-content: center;
    
                img{
                    max- 100%;
                    max-height: 100%;
                }
    
                .tools,
                .failed,
                .loading{
                    top: 0;
                    left: 0;
                     100%;
                    height: 100%;
                    display: flex;
                    color: #fff;
                    font-size: 2rem;
                    align-items: center;
                    position: absolute;
                    justify-content: center;
                    background: rgba(0, 0, 0, .5);
                }
    
                .failed{
                    color: #ccc;
                    font-size: 14px;
                    background: #fff;
                }
    
                .tools{
                    opacity: 0;
                    transition: all .3s;
                    pointer-events: none;
    
                    .el-button{
                        color: #fff;
                        font-size: 18px;
                        cursor: pointer;
    
                        &:hover{
                            transform: scale(1.2);
                            text-shadow: 0 0 1px #fff;
                        }
                    }
                }
    
                &:hover{
    
                    .tools{
                        opacity: 1;
                        pointer-events: auto;
                    }
                }
            }
    
            .add-wrapper{
                font-size: 2rem;
                cursor: pointer;
                color: #DCDFE6;
                transition: all .3s;
                align-items: center;
                display: inline-flex;
                border-style: dashed;
                justify-content: center;
    
                &:hover{
                    color: #409EFF;
                    border-color: #409EFF;
                }
    
                &[disabled]{
                    pointer-events: none;
                }
            }
    
            .upload-tips{
                flex: 1;
                margin-left: 20px;
                display: inline-block;
               
                span{
                    color: #ccc;
                    font-size: 12px;
                    display: block;
                    line-height: 24px;
                }
            }
    
            &.multiple{
                display: block;
    
                .image-wrapper{
                    float: left;
                    margin: 0 20px 20px 0;
    
                    &:last-child{
                        margin: 0;
                    }
                }
    
                .add-wrapper{
                    float: left;
                    margin: 0 20px 20px 0;
                }
    
                .upload-tips{
                     100%;
                    float: left;
                    display: block;
                    margin: 0;
                }
            }
        }
    </style>
    

      

     
     
    页面引用
    import imageUpload from "@/components/image-upload";
      components: { imageUpload },
    <image-upload
                v-model="goodslistPhoto"
                multiple
                :limit="20"
                folder="goodslistPhoto"
              />
     
    不求大富大贵,但求一生平凡
  • 相关阅读:
    【USACO10JAN】Cheese Towers S 奶酪塔 (背包dp)
    【SDOI2015】排序(dfs+结论)
    【NOI2014】购票(树形dp+树剖+斜率优化)
    【BZOJ3329】Xorequ(数位dp+矩阵快速幂)
    [NOI 2012] 骑行川藏
    BZOJ
    [学习笔记] 上下界网络流
    [八省联考 2018] 劈配
    P4313 文理分科
    [SDOI 2015] 序列统计
  • 原文地址:https://www.cnblogs.com/ylblogs/p/15572393.html
Copyright © 2011-2022 走看看