<!--
@name: fullScreenView
@description: 全屏视图组件
@author: zc
@time: 2023/11/30
@描述: 支持批量浏览 & 最大3倍缩放 & 支持拖拽 & 底部列表拖拽滚动
@引入:

    <fullScreenView :fullScreenViewProps="fullScreenViewProps" ref="fullScreenView"></fullScreenView>

    import fullScreenView from "@/components/fullScreenView/fullScreenView.vue";

    components: {
      fullScreenView,
    },

    fullScreenViewProps:[
      'https://img1.baidu.com/it/u=2559867097,3726275945&fm=253&fmt=auto&app=138&f=JPEG?w=1333&h=500',
      'https://img2.baidu.com/it/u=1118182176,4151078899&fm=253&fmt=auto&app=138&f=JPEG?w=750&h=500',
      'https://marketplace.canva.cn/peDdg/MADx4dpeDdg/1/screen_2x/canva-straight-railroad-MADx4dpeDdg.jpg',
      'https://img1.baidu.com/it/u=2774664417,792278893&fm=253&fmt=auto&app=138&f=JPEG?w=2022&h=500',
      'https://img2.baidu.com/it/u=3038223445,2416689412&fm=253&fmt=auto&app=120&f=JPEG?w=1920&h=1080',
    ],

    fullScreenViewClick(index){
      this.$refs['fullScreenView'].initialize(index);
      //index 非必传 不传时优先展示第一张
      this.$refs['fullScreenView'].initialize();
    },

-->
<template>
  <transition name="fade" mode="in-out">
    <div class="fullScreenView" v-if="showType">
      <!--复位按钮-->
      <p class="position-refresh-p el-icon-refresh" @click="clickLookImg(lookIndex)"></p>
      <!--下载按钮-->
      <p class="position-download-p el-icon-download" @click="downloadImage" v-if="!imgNullType"></p>
      <!--关闭按钮-->
      <p class="position-off-p el-icon-circle-close" @click="outButton"></p>
      <div class="max-img-box" ref="viewBox">
        <transition name="fade" mode="in-out">
          <img :src="lookImg" ref="viewImg"
               v-if="imgShowType"
               :style="'top:'+top+'px;left:'+left+'px;height:'+(height+(heightRatio*ratio))+'px;width:'+(width+(widthRatio*ratio))+'px;'"
               @mousedown.stop="dragDown"
               @mouseleave.stop="dragUp"
               @wheel="zoomScroll">
          <p v-if="imgNullType" class="img-null-text" :style="'height:'+maxHeight+'px;width:'+maxWidth+'px;line-height:'+maxHeight+'px;'">加载失败...</p>
        </transition>
      </div>
      <div class="list-img-min-box full-screen-scrollbar-box"
           v-if="fullScreenViewProps[1]"
           ref="listImgBox"
           @mousedown.stop="listBoxDragDown"
           @mouseleave.stop="listBoxDragUp">
        <p class="null-p"></p>
        <img :class="index === lookIndex ? 'lookImg' : ''"
             v-for="(item,index) in fullScreenViewProps"
             :src="item"
             @click="clickLookImg(index)">
        <p class="null-p"></p>
      </div>
    </div>
  </transition>
</template>
<script>
  export default {
    name: 'fullScreenView',
    props: {
      fullScreenViewProps:{},
    },
    data () {
      return {
        showType:false,
        imgShowType:false,
        imgNullType:false,
        //当前选中
        lookIndex:null,
        lookImg:"",
        //定位
        top:0,
        left:0,
        //尺寸
        width:0,
        height:0,
        //最大画布尺寸
        maxWidth:0,
        maxHeight:0,
        //当前鼠标坐标
        clientX:null,
        clientY:null,
        //放大倍率
        ratio:1,
        widthRatio:null,
        heightRatio:null,
        //预览图片组坐标
        listClientX:null,
        listClientY:null,
      }
    },
    created(){

    },
    mounted(){

    },
    methods:{
      //初始化
      initialize(index){
        let self = this;
        this.$set(this,'showType',true);
        setTimeout(function(){
          self.clickLookImg(index?index:null);
        },200);
      },
      //退出按钮
      outButton(){
        this.$set(this,'showType',false);
        this.$set(this,'lookImg',"");
        this.$set(this,'lookIndex',null);
        this.$set(this,'width',0);
        this.$set(this,'height',0);
      },
      //初始化图片位置
      clickLookImg(index){
        let self = this;
        if(index && index === this.lookIndex){
          return
        }
        //计算属性
        this.$set(this,'imgShowType',false);
        this.$set(this,'imgNullType',false);
        this.$set(this,'maxWidth',this.$refs["viewBox"].offsetWidth);
        this.$set(this,'maxHeight',this.$refs["viewBox"].offsetHeight);
        let newIndex = index?index:0;
        let newImg = index?this.fullScreenViewProps[index]:this.fullScreenViewProps[0];
        let img = new Image();
        let res = {};
        // 图片地址
        img.src = newImg;
        img.onload = function () {
          res = {
            width: img.width,
            height: img.height,
          }
          if(self.maxWidth >= res.width && self.maxHeight >= res.height){
            let w = self.cal.accSub(self.maxWidth,res.width);
            let h = self.cal.accSub(self.maxHeight,res.height);
            self.$set(self,'width',res.width);
            self.$set(self,'height',res.height);
            self.$set(self,'top',h>2?self.cal.accDiv(h,2):0);
            self.$set(self,'left',w>2?self.cal.accDiv(w,2):0);
            self.$set(self,'lookImg',newImg);
            self.$set(self,'lookIndex',newIndex);
            self.$set(self,'imgShowType',true);
            self.initializeRation(res.width,res.height);
          }else if(self.maxWidth >= res.width && self.maxHeight < res.height){
            let a = self.cal.accDiv(res.width,res.height)
            let b = self.cal.accSub(res.height,(self.maxHeight-100))
            let c = self.cal.accMul(a,b);
            let width = self.cal.accSub(res.width,c);
            let height = self.cal.accSub(res.height,b);
            let w = self.cal.accSub(self.maxWidth,width)
            let h = self.cal.accSub(self.maxHeight,height);
            self.$set(self,'width',width);
            self.$set(self,'height',height);
            self.$set(self,'top',h>2?self.cal.accDiv(h,2):0);
            self.$set(self,'left',w>2?self.cal.accDiv(w,2):0);
            self.$set(self,'lookImg',newImg);
            self.$set(self,'lookIndex',newIndex);
            self.$set(self,'imgShowType',true);
            self.initializeRation(width,height);
          }else if(self.maxWidth < res.width && self.maxHeight >= res.height){
            let a = self.cal.accDiv(res.height,res.width)
            let b = self.cal.accSub(res.width,(self.maxWidth-100))
            let c = self.cal.accMul(a,b);
            let width = self.cal.accSub(res.width,b);
            let height = self.cal.accSub(res.height,c);
            let w = self.cal.accSub(self.maxWidth,width)
            let h = self.cal.accSub(self.maxHeight,height);
            self.$set(self,'width',width);
            self.$set(self,'height',height);
            self.$set(self,'top',h>2?self.cal.accDiv(h,2):0);
            self.$set(self,'left',w>2?self.cal.accDiv(w,2):0);
            self.$set(self,'lookImg',newImg);
            self.$set(self,'lookIndex',newIndex);
            self.$set(self,'imgShowType',true);
            self.initializeRation(width,height);
          }else{
            let x = self.cal.accSub(res.width,self.maxWidth);
            let y = self.cal.accSub(res.height,self.maxHeight);
            if(x >= y){
              let a = self.cal.accDiv(res.height,res.width)
              let b = self.cal.accSub(res.width,(self.maxWidth-100))
              let c = self.cal.accMul(a,b);
              let width = self.cal.accSub(res.width,b);
              let height = self.cal.accSub(res.height,c);
              let w = self.cal.accSub(self.maxWidth,width)
              let h = self.cal.accSub(self.maxHeight,height);
              self.$set(self,'width',width);
              self.$set(self,'height',height);
              self.$set(self,'left',w>2?self.cal.accDiv(w,2):0);
              self.$set(self,'top',h>2?self.cal.accDiv(h,2):0);
              self.$set(self,'lookImg',newImg);
              self.$set(self,'lookIndex',newIndex);
              self.$set(self,'imgShowType',true);
              self.initializeRation(width,height);
            }else{
              let a = self.cal.accDiv(res.width,res.height)
              let b = self.cal.accSub(res.height,(self.maxHeight-100))
              let c = self.cal.accMul(a,b);
              let width = self.cal.accSub(res.width,c);
              let height = self.cal.accSub(res.height,b);
              let w = self.cal.accSub(self.maxWidth,width)
              let h = self.cal.accSub(self.maxHeight,height);
              self.$set(self,'width',width);
              self.$set(self,'height',height);
              self.$set(self,'left',w>2?self.cal.accDiv(w,2):0);
              self.$set(self,'top',h>2?self.cal.accDiv(h,2):0);
              self.$set(self,'lookImg',newImg);
              self.$set(self,'lookIndex',newIndex);
              self.$set(self,'imgShowType',true);
              self.initializeRation(width,height);
            }
          }
        }
        img.onerror = function () {
          self.$set(self,'imgNullType',true);
        }
      },
      //初始化缩放倍率
      initializeRation(w,h){
        this.$set(this,'ratio',0);
        this.$set(this,'widthRatio',this.cal.accDiv(w,10));
        this.$set(this,'heightRatio',this.cal.accDiv(h,10));
      },
      //鼠标滚动事件
      zoomScroll(e){
        if(Math.sign(e.wheelDelta) === 1 && Math.sign(e.wheelDeltaY) === 1){
          //上滚动
          if(this.ratio<20){
            this.$set(this,'ratio',this.cal.accAdd(this.ratio,1));
            let top = this.cal.accDiv(this.heightRatio,2);
            let left = this.cal.accDiv(this.widthRatio,2);
            this.$set(this,'top',this.cal.accSub(this.top,top));
            this.$set(this,'left',this.cal.accSub(this.left,left));
          }
        }else if(Math.sign(e.wheelDelta) === -1 && Math.sign(e.wheelDeltaY) === -1){
          //下滚动
          if(this.ratio>0){
            this.$set(this,'ratio',this.cal.accSub(this.ratio,1));
            let top = this.cal.accDiv(this.heightRatio,2);
            let left = this.cal.accDiv(this.widthRatio,2);
            this.$set(this,'top',this.cal.accAdd(this.top,top));
            this.$set(this,'left',this.cal.accAdd(this.left,left));
          }
        }
      },
      /*************图片拖拽事件*************/
      //按下时绑定事件
      dragDown(e) {
        if (e.button === 0) {  //0鼠标左键 1中键 2右键
          this.$set(this, 'clientX', e.clientX);
          this.$set(this, 'clientY', e.clientY);
          this.$refs.viewImg.addEventListener('mousemove', this.dragMove, false)
          this.$refs.viewImg.addEventListener('mouseup', this.dragUp, false)
        }
      },
      //弹起时删除事件
      dragUp(e) {
        if (e.button === 0) {  //0鼠标左键 1中键 2右键
          this.$refs.viewImg.removeEventListener('mousemove', this.dragMove, false)
          this.$refs.viewImg.removeEventListener('mouseup', this.dragUp, false)
        }
      },
      //移动事件
      dragMove(event) {
        if (event.button === 0) {  //0鼠标左键 1中键 2右键
          if(event.clientX > this.clientX){
            let num = this.cal.accSub(event.clientX,this.clientX);
            let num1 = this.cal.accAdd(this.width,this.left);
            let num2 = this.cal.accAdd(num1,num);
            // if(num2 < this.maxWidth){
            //   this.$set(this,'left',this.cal.accAdd(num,this.left));
            // }
            this.$set(this,'left',this.cal.accAdd(num,this.left));
          }
          if(event.clientX < this.clientX){
            let num = this.cal.accSub(this.clientX,event.clientX);
            let num1 = this.cal.accSub(this.left,num);
            // if(num1 > 0){
            //   this.$set(this,'left',this.cal.accSub(this.left,num));
            // }
            this.$set(this,'left',this.cal.accSub(this.left,num));
          }
          if(event.clientY > this.clientY){
            let num = this.cal.accSub(event.clientY,this.clientY);
            let num1 = this.cal.accAdd(this.height,this.top);
            let num2 = this.cal.accAdd(num1,num);
            // if(num2 < this.maxHeight){
            //   this.$set(this,'top',this.cal.accAdd(num,this.top));
            // }
            this.$set(this,'top',this.cal.accAdd(num,this.top));
          }
          if(event.clientY < this.clientY){
            let num = this.cal.accSub(this.clientY,event.clientY);
            let num1 = this.cal.accSub(this.top,num);
            // if(num1 > 0){
            //   this.$set(this,'top',this.cal.accSub(this.top,num));
            // }
            this.$set(this,'top',this.cal.accSub(this.top,num));
          }
          this.$set(this, 'clientX', event.clientX);
          this.$set(this, 'clientY', event.clientY);
        }
      },
      /*************滚动条拖拽事件*************/
      listBoxDragDown(e){
        if (e.button === 0) {  //0鼠标左键 1中键 2右键
          this.$set(this, 'listClientX', e.clientX);
          this.$set(this, 'listClientY', e.clientY);
          this.$refs.listImgBox.addEventListener('mousemove', this.listBoxDragMove, false)
          this.$refs.listImgBox.addEventListener('mouseup', this.listBoxDragUp, false)
        }
      },
      listBoxDragUp(e){
        if (e.button === 0) {  //0鼠标左键 1中键 2右键
          this.$refs.listImgBox.removeEventListener('mousemove', this.listBoxDragMove, false)
          this.$refs.listImgBox.removeEventListener('mouseup', this.listBoxDragUp, false)
        }
      },
      listBoxDragMove(event){
        if (event.button === 0) {  //0鼠标左键 1中键 2右键
          let scrollNum = this.$refs.listImgBox.scrollLeft;
          if(event.clientX > this.listClientX){
            let num = this.cal.accSub(event.clientX,this.listClientX);
            this.$refs.listImgBox.scrollLeft = this.cal.accSub(scrollNum,num)
            this.$set(this, 'listClientX', event.clientX);
          }
          if(event.clientX < this.listClientX){
            let num = this.cal.accSub(this.listClientX,event.clientX);
            this.$refs.listImgBox.scrollLeft = this.cal.accAdd(scrollNum,num)
            this.$set(this, 'listClientX', event.clientX);
          }
        }
      },
      /*************滚动条拖拽事件*************/
      async downloadImage() {
        let currentDate = this.getCurrentTime()
        // 获取图片对象和画布对象
        const imgUrl = this.lookImg
        const response = await fetch(imgUrl)
        const blob = await response.blob()
        // 创建下载链接
        const url = window.URL.createObjectURL(blob)
        const link = document.createElement('a')
        link.href = url
        link.download = 'image '+currentDate+'.png'
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
        // 释放 Blob URL
        window.URL.revokeObjectURL(url)
      },
      /** 当前时间 */
      getCurrentTime () {
        const yy = new Date().getFullYear()
        const mm = new Date().getMonth() + 1
        const dd = new Date().getDate()
        const hh = new Date().getHours()
        const mf = new Date().getMinutes() < 10 ? '0' + new Date().getMinutes() : new Date().getMinutes()
        const ss = new Date().getSeconds() < 10 ? '0' + new Date().getSeconds() : new Date().getSeconds()
        return yy + '-' + mm + '-' + dd + ' ' + hh + ':'+ mf + ':'+ ss
      },
    },
  }
</script>
<style scoped lang="scss">
  .fade-enter-active, .fade-leave-active {
    transition: opacity .3s;
  }
  .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
    opacity: 0;
  }
  .fullScreenView{
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    position:fixed;
    top:0;
    left:0;
    z-index:99999;
    width:100%;
    height:100%;
    background-color: rgba(0,0,0,0.9);
    display: flex;
    flex-direction: column;
    .position-off-p{
      position: absolute;
      right:20px;
      top:20px;
      color:#fff;
      width:30px;
      height:30px;
      line-height:30px;
      text-align: center;
      font-size:30px;
      cursor: pointer;
      z-index: 999;
    }
    .position-off-p:hover{
      color:#0183FA;
    }
    .position-refresh-p{
      position: absolute;
      left:20px;
      top:20px;
      color:#fff;
      width:30px;
      height:30px;
      line-height:30px;
      text-align: center;
      font-size:30px;
      cursor: pointer;
      z-index: 999;
    }
    .position-refresh-p:hover{
      color:#0183FA;
    }
    .position-download-p{
      position: absolute;
      left:80px;
      top:20px;
      color:#fff;
      width:30px;
      height:30px;
      line-height:30px;
      text-align: center;
      font-size:30px;
      cursor: pointer;
      z-index: 999;
    }
    .position-download-p:hover{
      color:#0183FA;
    }
    .max-img-box{
      flex:1;
      overflow: hidden;
      position: relative;
      img{
        position: absolute;
        -webkit-user-drag: none;
      }
      .img-null-text{
        text-align: center;
        color:#dedede;
        font-size:16px;
      }
    }
    .list-img-min-box{
      display: flex;
      background-color: rgba(255,255,255,0.1);
      height:150px;
      padding:20px;
      overflow-x:scroll;
      overflow-y:hidden;
      white-space: nowrap;
      .null-p{
        flex:1;
      }
      img{
        -webkit-user-drag: none;
        display: inline-block;
        width:200px;
        height:112px;
        margin:auto 10px;
        cursor: pointer;
        filter: grayscale(100%);
      }
      img:hover{
        box-shadow: 0 0 15px rgba(255,255,255,0.6);
        filter: grayscale(0%);
      }
      .lookImg{
        filter: grayscale(0%);
        box-shadow: 0 0 15px rgba(255,255,255,0.6);
      }
    }
  }

  //竖向
  .full-screen-scrollbar-box{
    overflow-y: scroll;
  }
  .full-screen-scrollbar-box::-webkit-scrollbar{
    width: 6px;     /*高宽分别对应横竖滚动条的尺寸*/
    height: 6px;
  }
  .full-screen-scrollbar-box::-webkit-scrollbar-thumb{
    border-radius: 5px;
    -webkit-box-shadow: inset 0 0 5px rgba(255,255,255,0.1);
    background:  rgba(255,255,255,0.1);
  }
  .full-screen-scrollbar-box::-webkit-scrollbar-track{
    -webkit-box-shadow: inset 0 0 5px #303030;
    border-radius: 0;
    background: #303030;
  }
</style>
