<template> 
 | 
    <view class="uni-file-picker__container"> 
 | 
        <view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle"> 
 | 
            <view class="file-picker__box-content" :style="borderStyle"> 
 | 
                <image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image> 
 | 
                <view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)"> 
 | 
                    <view class="icon-del"></view> 
 | 
                    <view class="icon-del rotate"></view> 
 | 
                </view> 
 | 
                <view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress"> 
 | 
                    <progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" 
 | 
                     :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" /> 
 | 
                </view> 
 | 
                <view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)"> 
 | 
                    点击重试 
 | 
                </view> 
 | 
            </view> 
 | 
        </view> 
 | 
        <view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle"> 
 | 
            <view class="file-picker__box-content is-add" :style="borderStyle" @click="choose"> 
 | 
                <slot> 
 | 
                    <view class="icon-add"></view> 
 | 
                    <view class="icon-add rotate"></view> 
 | 
                </slot> 
 | 
            </view> 
 | 
        </view> 
 | 
    </view> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
    export default { 
 | 
        name: "uploadImage", 
 | 
        emits:['uploadFiles','choose','delFile'], 
 | 
        props: { 
 | 
            filesList: { 
 | 
                type: Array, 
 | 
                default () { 
 | 
                    return [] 
 | 
                } 
 | 
            }, 
 | 
            disabled:{ 
 | 
                type: Boolean, 
 | 
                default: false 
 | 
            }, 
 | 
            disablePreview: { 
 | 
                type: Boolean, 
 | 
                default: false 
 | 
            }, 
 | 
            limit: { 
 | 
                type: [Number, String], 
 | 
                default: 9 
 | 
            }, 
 | 
            imageStyles: { 
 | 
                type: Object, 
 | 
                default () { 
 | 
                    return { 
 | 
                        width: 'auto', 
 | 
                        height: 'auto', 
 | 
                        border: {} 
 | 
                    } 
 | 
                } 
 | 
            }, 
 | 
            delIcon: { 
 | 
                type: Boolean, 
 | 
                default: true 
 | 
            }, 
 | 
            readonly:{ 
 | 
                type:Boolean, 
 | 
                default:false 
 | 
            } 
 | 
        }, 
 | 
        computed: { 
 | 
            styles() { 
 | 
                let styles = { 
 | 
                    width: 'auto', 
 | 
                    height: 'auto', 
 | 
                    border: {} 
 | 
                } 
 | 
                return Object.assign(styles, this.imageStyles) 
 | 
            }, 
 | 
            boxStyle() { 
 | 
                const { 
 | 
                    width = 'auto', 
 | 
                        height = 'auto' 
 | 
                } = this.styles 
 | 
                let obj = {} 
 | 
                if (height === 'auto') { 
 | 
                    if (width !== 'auto') { 
 | 
                        obj.height = this.value2px(width) 
 | 
                        obj['padding-top'] = 0 
 | 
                    } else { 
 | 
                        obj.height = 0 
 | 
                    } 
 | 
                } else { 
 | 
                    obj.height = this.value2px(height) 
 | 
                    obj['padding-top'] = 0 
 | 
                } 
 | 
  
 | 
                if (width === 'auto') { 
 | 
                    if (height !== 'auto') { 
 | 
                        obj.width = this.value2px(height) 
 | 
                    } else { 
 | 
                        obj.width = '33.3%' 
 | 
                    } 
 | 
                } else { 
 | 
                    obj.width = this.value2px(width) 
 | 
                } 
 | 
  
 | 
                let classles = '' 
 | 
                for(let i in obj){ 
 | 
                    classles+= `${i}:${obj[i]};` 
 | 
                } 
 | 
                return classles 
 | 
            }, 
 | 
            borderStyle() { 
 | 
                let { 
 | 
                    border 
 | 
                } = this.styles 
 | 
                let obj = {} 
 | 
                const widthDefaultValue = 1 
 | 
                const radiusDefaultValue = 3 
 | 
                if (typeof border === 'boolean') { 
 | 
                    obj.border = border ? '1px #eee solid' : 'none' 
 | 
                } else { 
 | 
                    let width = (border && border.width) || widthDefaultValue 
 | 
                    width = this.value2px(width) 
 | 
                    let radius = (border && border.radius) || radiusDefaultValue 
 | 
                    radius = this.value2px(radius) 
 | 
                    obj = { 
 | 
                        'border-width': width, 
 | 
                        'border-style': (border && border.style) || 'solid', 
 | 
                        'border-color': (border && border.color) || '#eee', 
 | 
                        'border-radius': radius 
 | 
                    } 
 | 
                } 
 | 
                let classles = '' 
 | 
                for(let i in obj){ 
 | 
                    classles+= `${i}:${obj[i]};` 
 | 
                } 
 | 
                return classles 
 | 
            } 
 | 
        }, 
 | 
        methods: { 
 | 
            uploadFiles(item, index) { 
 | 
                this.$emit("uploadFiles", item) 
 | 
            }, 
 | 
            choose() { 
 | 
                this.$emit("choose") 
 | 
            }, 
 | 
            delFile(index) { 
 | 
                this.$emit('delFile', index) 
 | 
            }, 
 | 
            prviewImage(img, index) { 
 | 
                let urls = [] 
 | 
                if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){ 
 | 
                    this.$emit("choose") 
 | 
                } 
 | 
                if(this.disablePreview) return 
 | 
                this.filesList.forEach(i => { 
 | 
                    urls.push(i.url) 
 | 
                }) 
 | 
  
 | 
                uni.previewImage({ 
 | 
                    urls: urls, 
 | 
                    current: index 
 | 
                }); 
 | 
            }, 
 | 
            value2px(value) { 
 | 
                if (typeof value === 'number') { 
 | 
                    value += 'px' 
 | 
                } else { 
 | 
                    if (value.indexOf('%') === -1) { 
 | 
                        value = value.indexOf('px') !== -1 ? value : value + 'px' 
 | 
                    } 
 | 
                } 
 | 
                return value 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
</script> 
 | 
  
 | 
<style lang="scss"> 
 | 
    .uni-file-picker__container { 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: flex; 
 | 
        box-sizing: border-box; 
 | 
        /* #endif */ 
 | 
        flex-wrap: wrap; 
 | 
        margin: -5px; 
 | 
    } 
 | 
  
 | 
    .file-picker__box { 
 | 
        position: relative; 
 | 
        // flex: 0 0 33.3%; 
 | 
        width: 33.3%; 
 | 
        height: 0; 
 | 
        padding-top: 33.33%; 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        box-sizing: border-box; 
 | 
        /* #endif */ 
 | 
    } 
 | 
  
 | 
    .file-picker__box-content { 
 | 
        position: absolute; 
 | 
        top: 0; 
 | 
        right: 0; 
 | 
        bottom: 0; 
 | 
        left: 0; 
 | 
        margin: 5px; 
 | 
        border: 1px #eee solid; 
 | 
        border-radius: 5px; 
 | 
        overflow: hidden; 
 | 
    } 
 | 
  
 | 
    .file-picker__progress { 
 | 
        position: absolute; 
 | 
        bottom: 0; 
 | 
        left: 0; 
 | 
        right: 0; 
 | 
        /* border: 1px red solid; */ 
 | 
        z-index: 2; 
 | 
    } 
 | 
  
 | 
    .file-picker__progress-item { 
 | 
        width: 100%; 
 | 
    } 
 | 
  
 | 
    .file-picker__mask { 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: flex; 
 | 
        /* #endif */ 
 | 
        justify-content: center; 
 | 
        align-items: center; 
 | 
        position: absolute; 
 | 
        right: 0; 
 | 
        top: 0; 
 | 
        bottom: 0; 
 | 
        left: 0; 
 | 
        color: #fff; 
 | 
        font-size: 12px; 
 | 
        background-color: rgba(0, 0, 0, 0.4); 
 | 
    } 
 | 
  
 | 
    .file-image { 
 | 
        width: 100%; 
 | 
        height: 100%; 
 | 
    } 
 | 
  
 | 
    .is-add { 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: flex; 
 | 
        /* #endif */ 
 | 
        align-items: center; 
 | 
        justify-content: center; 
 | 
    } 
 | 
  
 | 
    .icon-add { 
 | 
        width: 50px; 
 | 
        height: 5px; 
 | 
        background-color: #f1f1f1; 
 | 
        border-radius: 2px; 
 | 
    } 
 | 
  
 | 
    .rotate { 
 | 
        position: absolute; 
 | 
        transform: rotate(90deg); 
 | 
    } 
 | 
  
 | 
    .icon-del-box { 
 | 
        /* #ifndef APP-NVUE */ 
 | 
        display: flex; 
 | 
        /* #endif */ 
 | 
        align-items: center; 
 | 
        justify-content: center; 
 | 
        position: absolute; 
 | 
        top: 3px; 
 | 
        right: 3px; 
 | 
        height: 26px; 
 | 
        width: 26px; 
 | 
        border-radius: 50%; 
 | 
        background-color: rgba(0, 0, 0, 0.5); 
 | 
        z-index: 2; 
 | 
        transform: rotate(-45deg); 
 | 
    } 
 | 
  
 | 
    .icon-del { 
 | 
        width: 15px; 
 | 
        height: 2px; 
 | 
        background-color: #fff; 
 | 
        border-radius: 2px; 
 | 
    } 
 | 
</style> 
 |