<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>