VUE照片墙

标题组件介绍:该组件为照片墙组件,包括上传图片,删除图片,图片预览功能。组件需要引入vue和element(使用了element的字体图标)

属性如下:

  • imgList:必须值、初始的图片渲染列表,Array
  • width:单元图片的宽度值默认为100px,height:单元图片的宽度值默认为100px;Number
  • right:照片墙右侧距离默认值10px,bottom:照片墙下侧距离默认值10px;Number
  • color:上传区域的文本及边框颜色,默认值#66b1ff,支持颜色色值
  • size:上传区域的文本字体大小,默认值20px;Number
  • uploadText:上传区域的文本,默认值:点击上传。String
  • borderStyle:上传区域的边框样式默认值直线,支持CSS一切边框样式。包括直线,曲线…[dashed \solid\dotted\double\groove\ridge\inset\outset]
  • showIcon:上传区域是否显示图标,默认值不显示,如果设置则显示图标不显示文字。Boolean
  • showAllDel:是否直接显示所有图片的删除按钮,默认值不显示,不显示的情况是由鼠标进入图片显示。Boolean
  • base64:上传图片时返回给父组件的格式,默认是浏览器创建url,使用base64可以通过这个属性设置。Boolean
  • showCurrentBox:是否展示当前图片位置
  • perviewMethods:触发预览图片的方式,默认为双击。可以选择click或者dblclick
    方法:
  • getDelImgIdList(delImgIdList)传回去的delImgIdList是需要删除图片的id
  • addImg(addImgList)传回去的addImgList是新增图片的信息,包括随机生成的Id与url。url参考base64属性
<template>
  <div class="yh-photoWall">
    <!-- 图片渲染包括删除区域 -->
      <div v-for="(img,index) in list" :key="img.id" class="yh-photoWall-img" 
      :style="{height:height+'px',width:width+'px',marginRight:right+'px',marginBottom:bottom+'px'}"  
      @mouseover ="showDelIcon(img.id)">
        <img :src="img.url" style="width:100%;height:100%" @mouseleave="delImgId=null" @dblclick="showPreviewImg(img.url,index)"/>
        <i class="el-icon-close yh-photoWall-x" v-if="delImgId === img.id || showAllDel"  @mouseenter ="showDelIcon(img.id)"  @mouseleave="delImgId=null" @click="delImg(img.id)"></i>
      </div>
      <!-- 上传图片区域 -->
      <div class="yh-photoWall-add" 
      :style="{height:height+'px',width:width+'px',marginRight:right+'px',marginBottom:bottom+'px',lineHeight:height+'px',color:color,fontSize:size+'px',border:borderStyle, background:uploadBgc}"
      @click="clickFile"
      >
          <i v-if="showIcon" class="el-icon-plus"></i>
          <span v-else>{{uploadText}}</span>
      </div>
      <!-- <input type="file" class="yh-photoWall-file"> -->
      <!-- 预览图片区域 -->
      <div v-if="showFlag" class="showFlag" >
        <img :src="previewImgUrl"  class="previewImg" />
        <i class="el-icon-close yh-close-perview" @click="closeperview"></i>
        <i class="el-icon-zoom-in yh-big-perview" @click="perImgBig"></i>
        <i class="el-icon-zoom-out yh-samll-perview" @click="perImgSamll"></i>
        <i class="el-icon-arrow-left yh-left-perview" @click="leftPerImg"></i>
        <i class="el-icon-arrow-right yh-right-perview" @click="rightPerImg"></i>
        <div class="yh-current-box" :style="{width:list.length*30+'px'}" v-if="showCurrentBox">
          <span :class="['yh-current-perview',{'yh-current-perview-active':(i-1)===currentImg}]" v-for="i in list.length" :key="i" @click="jumpPreImg(i)"></span>
        </div>
      </div>
  </div>
</template>

<script>
/*  组件介绍:该组件为照片墙组件,包括上传图片,删除图片,图片预览功能。
 *  属性如下:
 *  imgList:必须值、初始的图片渲染列表,Array
 *  width:单元图片的宽度值默认为100px,height:单元图片的宽度值默认为100px;Number
 *  right:照片墙右侧距离默认值10px,bottom:照片墙下侧距离默认值10px;Number
 *  color:上传区域的文本及边框颜色,默认值#66b1ff,支持rgb\rgba\十六进制(3位或者6位)\hsl\hsla
 *  size:上传区域的文本字体大小,默认值20px;Number
 *  uploadText:上传区域的文本,默认值:点击上传。String
 *  borderStyle:上传区域的边框样式默认值直线,支持CSS一切边框样式。包括直线,曲线.... String[dashed \solid\dotted\double\groove\ridge\inset\outset]
 *  showIcon:上传区域是否显示图标,默认值不显示,如果设置则显示图标不显示文字。Boolean
 *  showAllDel:是否直接显示所有图片的删除按钮,默认值不显示,不显示的情况是由鼠标进入图片显示。Boolean
 *  base64:上传图片时返回给父组件的格式,默认是浏览器创建url,使用base64可以通过这个属性设置。Boolean
 *  showCurrentBox:是否展示当前图片位置。Boolean
 *  perviewMethods:触发预览图片的方式,默认为双击。可以选择click或者dblclick
 *  uploadBgc:修改上传图片区域的背景色,默认#fff,支持rgb\rgba\十六进制(3位或者6位)\hsl\hsla
 *  方法:
 *  getDelImgIdList(delImgIdList)传回去的delImgIdList是需要删除图片的id
 *  addImg(addImgList)传回去的addImgList是新增图片的信息,包括随机生成的Id与url。url参考base64属性
 */
 function CheckIsColor(bgVal) {
      let type='';
      if(/^rgb\(/.test(bgVal)){
          //如果是rgb开头,200-249,250-255,0-199
         type = "^[rR][gG][Bb][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){2}[\\s]*(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)[\\s]*[\)]{1}$";
      }else if(/^rgba\(/.test(bgVal)){
          //如果是rgba开头,判断0-255:200-249,250-255,0-199 判断0-1:0 1 1.0 0.0-0.9
         type = "^[rR][gG][Bb][Aa][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){3}[\\s]*(1|1.0|0|0.[0-9])[\\s]*[\)]{1}$";
      }else if(/^#/.test(bgVal)){
          //六位或者三位
         type = "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$"
      }else if(/^hsl\(/.test(bgVal)){
          //判断0-360 判断0-100%(0可以没有百分号)
         type = "^[hH][Ss][Ll][\(]([\\s]*(2[0-9][0-9]|360|3[0-5][0-9]|[01]?[0-9][0-9]?)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*)[\)]$";
      }else if(/^hsla\(/.test(bgVal)){
          type = "^[hH][Ss][Ll][Aa][\(]([\\s]*(2[0-9][0-9]|360|3[0-5][0-9]|[01]?[0-9][0-9]?)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*,){2}([\\s]*(1|1.0|0|0.[0-9])[\\s]*)[\)]$";
      }
      let re = new RegExp(type);
      if (bgVal.match(re) == null){
         return false
      }else{
         return true
     }
    }
  export default {
    name:'photoWall',
    props:{
      imgList:{
        require:true,
        type:Array,
      },
      width:{
        type:Number,
        default:100,
      },
      height:{
        type:Number,
        default:100,
      },
      right:{
        type:Number,
        default:10,
      },
      bottom:{
        type:Number,
        default:10,
      },
      color:{
        default:function(){
          return '#66b1ff'
        },
        validator:function(value){
          return CheckIsColor(value)
        }
      },
      size:{
        default:20,
        type:Number
      },
      uploadText:{
        default:'点击上传',
        type:String
      },
      borderStyle:{
        default:function(){
          return 'solid'
        },
        type:String,
        validator:function(value){
          return ["dashed","solid","dotted","double","groove","ridge","inset","outset"].indexOf(value) !== -1
        }
      },
      showIcon:{
        default:false,
        type:Boolean
      },
      showAllDel:{
        default:false,
        type:Boolean
      },
      base64:{
        default:false,
        type:Boolean
      },
      showCurrentBox:{
        default:true,
        type:Boolean
      },
      uploadBgc:{
        default:function(){
          return '#fff'
        },
        validator:function(value){
          return CheckIsColor(value)
        }
      }
    },
    data(){
      return {
        delImgId:null,
        list:this.imgList,
        delImgIdList:[],
        addImgList:[],
        showFlag:false,
        previewImgUrl:null,
        currentImg:null,
        dbWidth:'',
        dbHeight:'',
      }
    },
    mounted(){
     this.getWindowHW()
     window.addEventListener('resize',this.getWindowHW)
    },
    destroyed(){
      window.removeEventListener('resize',this.getWindowHW())
    },
    methods:{
      // 获取浏览器宽高
      getWindowHW(){
        this.dbWidth=window.innerWidth;
        this.dbHeight=window.innerHeight;
      },
      // 让删除图标展示
      showDelIcon(imgId){
        this.delImgId=imgId
      },
      // 删除图片
      delImg(imgId){
        this.delImgIdList.push(imgId);
        this.$emit('getDelImgIdList',this.delImgIdList) //将删除图片的id给父组件
        this.list=this.list.filter(img=>img.id!=imgId)
      },
      // 上传图片
      clickFile(){
        let yhphotoBox = document.querySelector('.yh-photoWall')   
        let uploadBtn = document.createElement('input')
        yhphotoBox.appendChild(uploadBtn)
        uploadBtn.setAttribute('type','file')
        uploadBtn.setAttribute('class','yh-photoWall-file')
        uploadBtn.click();
        let _that=this
        uploadBtn.onchange = function(){
          let that=this
          let imageList=["image/png","image/jpg","image/jpeg","image/gif"] //上传的图片类型白名单
          // console.log(that.files[0].type);
          if(!this.type||!imageList.some(item=>item===that.files[0].type)){
              return _that.$message.error('只支持png、jpeg、jpg、gif模式')
          }
          if(_that.base64 && that.files[0].size>128*1024){
            yhphotoBox.removeChild(uploadBtn)
            return _that.$message.warning('base64格式数据最大为128字节')
          }
          let url=''
          function uploadImg(url){
             _that.list.push({url,id:Math.random()*10000})
             _that.addImgList.push({url,id:Math.random()*10000})
             _that.$emit('addImg', _that.addImgList)
          }
          if(_that.base64){
            let reader =new FileReader();
            reader.readAsDataURL(that.files[0])
            reader.onload = function(){
              url=reader.result
              uploadImg(url)
              yhphotoBox.removeChild(uploadBtn)
            }
          }else{
               url=URL.createObjectURL(that.files[0]);
               uploadImg(url)
               yhphotoBox.removeChild(uploadBtn)
          }
        }
      },
      // 展示预览图片
      showPreviewImg(val,index){
        this.previewImgUrl=val;
        this.showFlag=true;
        this.currentImg=index;
      },
      // 关闭预览区域
      closeperview(){
        this.showFlag=false;
      },
      // 放大图片
      perImgBig(){
        // 放大预览图片
        const perImg=document.querySelector('.previewImg')
         const width=perImg.width
         const height=perImg.height
         const  nowWidth=width+50
         const computeRatio=nowWidth*height/width  //得到等比列的大小
         if(nowWidth>=(this.dbWidth-200)||computeRatio>=(this.dbHeight-200)){
            return
         }else{
           perImg.style.width=nowWidth+'px'
         }
      },
      // 缩小预览图片
      perImgSamll(){
        // 缩小图片
        const perImg=document.querySelector('.previewImg')
         const width=perImg.width
         const height=perImg.height
         if(width<=50||height<=50){
            return
         }else{
           const nowWidth=width-50
           perImg.style.width=nowWidth<=50?'50px':nowWidth+'px'
         }
      },
      // 像上一张
      leftPerImg(){
        document.querySelector('.previewImg').style.width='auto'
        this.currentImg=this.currentImg>0?--this.currentImg:this.list.length-1;
        this.previewImgUrl=this.list[this.currentImg].url;     
      },
      // 预览下一张
      rightPerImg(){
        document.querySelector('.previewImg').style.width='auto'
        this.currentImg=this.currentImg<this.list.length-1?++this.currentImg:0;
        this.previewImgUrl=this.list[this.currentImg].url;  
      },
      // 预览指定图片
      jumpPreImg(i){
        document.querySelector('.previewImg').style.width='auto'
        this.currentImg=i-1
        this.previewImgUrl=this.list[this.currentImg].url;  
      }
    }
  }
</script>

<style lang="less">
.yh-photoWall{
  .yh-photoWall-file{
      display: none;
    }
  .yh-photoWall-img{
    position: relative;
    display: inline-block;
     img{
       display: inline-block;
     }
     .yh-photoWall-x{
        position: absolute;
        top: 0;
        right: 0;
        transform: translate(50%,-50%);
        background-color: #333;
        color: #fff;
        border-radius: 50%;
     }
  }
  .yh-photoWall-add{
    text-align: center;
    display: inline-block;
    vertical-align: bottom;
    box-sizing: border-box;
  }
  .showFlag{
    width: 100%;
    height: 100%;
    background-color:rgba(0, 0, 0, 0.3);
    position: fixed;
    top: 0;
    left: 0;
      .previewImg{
        max-height: calc(100% - 200px);
        max-width: calc(100% - 200px);
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        z-index: 9999;
      }
    .yh-close-perview{
      position: absolute;
      top: 20px;
      right: 20px;
      font-size: 30px;
      color: #fff;
    }
    .yh-big-perview,.yh-samll-perview{
      position: absolute;
      bottom: 30px;
      color: #fff;
      font-size: 30px;
      left: 50%;
    }
    .yh-big-perview{
      transform: translate(calc(-50% - 55px));
    }
    .yh-samll-perview{
      transform: translate(calc(-50% + 55px));
    }
    .yh-left-perview,.yh-right-perview{
      position: absolute;
      top: 50%;
      color: #fff;
      background-color: rgb(92, 86, 86);
      border-radius: 50%;
      font-size: 30px;
      width: 50px;
      height: 50px;
      text-align: center;
      line-height: 50px;
    }
    .yh-left-perview{
      left: 50px;
    }
    .yh-right-perview{
      right: 50px;
    }
    .yh-current-perview{
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background-color: #666;
    }
    .yh-current-perview-active{
       background-color: #fff;
    }
    .yh-current-box{
      display: flex;
      position: absolute;
      bottom: 70px;
      left: 50%;
      justify-content: space-around;
      transform: translate(-50%);
    }
  }
}
</style>

测试用例

<template>
  <photo-wall :imgList="imgList" :width="200" :height="100" :right="20" @getDelImgIdList="getDelImgIdList" showIcon perviewMethods="click" :size="50" borderStyle="dashed"   @addImg="addImg" style="margin-left:20px;"/>
</template>

<script>
import photoWall from '@/components/photoWall.vue'
  export default {
    components:{
      photoWall,
    },
    data(){
      return {
        imgList:[
          {id:1,url:'https://fuss10.elemecdn.com/8/27/f01c15bb73e1ef3793e64e6b7bbccjpeg.jpeg'},
          // {id:2,url:'https://fuss10.elemecdn.com/1/8e/aeffeb4de74e2fde4bd74fc7b4486jpeg.jpeg'}
        ]
      }
    },
    methods:{
      getDelImgIdList(val){
        console.log(val);
      },
      addImg(val){
        console.log(val);
      }
    }
  }
</script>

<style lang="less">
  
</style>

你可能感兴趣的:(自定义组件,vue,elementui,javascript)