#
whycq
2024-01-17 01d453a6d5a751a78eab5f56ad0f35a0a2ebf281
uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
New file
@@ -0,0 +1,292 @@
<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>