vue 图片查看放大组件(包括拖拽,旋转,放大,切换下一张)

<template>
  <div v-if="showViewer" class="previewImg" :style="'top: '+ imgTop + 'px; left:'+ imgLeft+'px'" @mousewheel.prevent="wheelChange" @mousedown.self="mousedown" @mousemove.self="mousemove" @mouseleave.self="mouseleave" @mouseup.self="mouseleave">
    <span class="title">{{ titleName }}</span>
    <img src="../../assets/images/close.png" class="close-img" @click="doCloseImgView">
    <div ref="img" class="img-view">
      <div @mousedown.prevent="imgDownChange" @mousemove.prevent="imgMoveChange" @mouseleave.prevent="imgLeaveChange" @mouseup.prevent="imgLeaveChange">
        <el-image lazy :style="'top:'+ imgMarginTop +'px;left:'+ imgMarginLeft +'px;transform:scale(' + imgWidth + ') rotate('+imgTransform+'deg);'" :src="url[imgIndex]" />
      </div>
    </div>
    <template v-if="url.length > 1">
      <div class="arrowRight" @click="arrowChange(2)">
        <i class="el-icon-arrow-right" />
      </div>
      <div class="arrowRight" style="left:5%" @click="arrowChange(1)">
        <i class="el-icon-arrow-left" />
      </div>
    </template>
    <div class="operateBtn">
      <i class="el-icon-zoom-out" @click="zoomOut(1)" />
      <i class="el-icon-zoom-in" @click="zoomOut(2)" />
      <i :class="fullStatus?'el-icon-c-scale-to-original':'el-icon-full-screen'" @click="fullScreen" />
      <i class="el-icon-refresh-left" @click="imgRefresh(1)" />
      <i class="el-icon-refresh-right" @click="imgRefresh(2)" />
    </div>
  </div>
</template>
<script>
/*
  show-viewer: 是否展示状态,在需要展示时变为true 类型为布尔值
  url: 图片的路径,类型为数组
  imgIndex: 查看图片下标
  fullscreenStatus: false 是否放大全屏
  close-viewer: 关闭弹框事件 类型为方法  将布尔值变为false
  closeViewer() {
    this.showViewer = false
  }

  imgIndexChange 下标切换事件
  imgChange(type) {
    if (type === 1) {
      this.imgIndex -= 1
    } else if (type === 2) {
      this.imgIndex += 1
    }
  }
  <preview-img :show-viewer="" :url="" :close-viewer="" />

  import PreviewImg from '@/components/PreviewImg'
  components: {
    PreviewImg
  },
*/
export default {
  name: 'Index',
  props: {
    showViewer: { // 是否展示
      type: Boolean,
      default: false
    },
    url: { // 展示图片路径
      type: Array,
      default: null
    },
    titleName: {
      type: String,
      default: '大图预览'
    },
    imgIndex: {
      type: Number,
      default: 0
    },
    fullscreenStatus: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      imgTop: 100,
      imgLeft: 500,
      boxTop: 0,
      boxLeft: 0,
      mouseStatus: false,
      boxStatus: true,
      imgWidth: 0.5, // 图片放大比例
      fullStatus: false, // 是否全屏显示
      imgTransform: 0, // 旋转角度
      imgStatus: false, // 图片拖动状态
      imgMarginTop: 0, // 图片拖动marginTop
      imgMarginLeft: 0, // 图片拖动marginLeft
      imgScrollLeft: 0, // 图片按下位置left(用于计算)
      imgScrollTop: 0 // 图片按下位置top(用于计算)
    }
  },
  watch: {
    showViewer(newVal) {
      if (newVal && this.fullscreenStatus) {
        this.fullStatus = this.fullscreenStatus
        this.imgWidth = 1
      }
    }
  },
  mounted() {
    if (this.fullscreenStatus) {
      this.fullStatus = this.fullscreenStatus
      this.imgWidth = 1
    }
  },
  methods: {
    arrowChange(type) {
      // -1
      this.resetVal()
      if ((type === 1 && this.imgIndex !== 0) || (type === 2 && this.imgIndex !== this.url.length - 1)) {
        this.$emit('imgIndexChange', type)
      }
    },
    resetVal() {
      this.imgWidth = 0.5
      this.fullStatus = false
      this.imgTransform = 0
      this.imgStatus = false
      this.imgMarginTop = 0
      this.imgMarginLeft = 0
      this.imgScrollLeft = 0
      this.imgScrollTop = 0
    },
    // 图片旋转
    imgRefresh(status) {
      if (status === 1) {
        this.imgTransform += 90
      } else {
        this.imgTransform -= 90
      }
      this.imgTransform = Math.abs(this.imgTransform) === 360 ? 0 : this.imgTransform
      this.$refs.img.scrollTop = 0
      this.$refs.img.scrollLeft = 0
    },
    // 图片放大缩小
    zoomOut(status) {
      if (status === 1) {
        this.imgWidth = this.imgWidth <= 0.1 ? 0.1 : this.imgWidth - 0.2
      } else if (status === 2) {
        this.imgWidth += 0.2
      }
    },
    // 全屏|缩小
    fullScreen() {
      this.fullStatus = !this.fullStatus
      this.imgWidth = this.fullStatus ? 1 : 0.5
      this.imgMarginTop = 0
      this.imgMarginLeft = 0
    },
    // 滚轮滑动
    wheelChange(e) {
      const direction = e.deltaY > 0 ? 'down' : 'up'
      if (direction === 'up') {
        this.imgWidth += 0.2
      } else {
        this.imgWidth = this.imgWidth <= 0.1 ? 0.1 : this.imgWidth - 0.2
      }
    },
    // 图片区域按下
    imgDownChange(e) {
      this.imgStatus = true
      this.imgScrollLeft = e.pageX
      this.imgScrollTop = e.pageY
    },
    // 离开图片区域
    imgLeaveChange() {
      this.imgStatus = false
    },
    // 图片移动
    imgMoveChange(e) {
      if (this.imgStatus) {
        if (e.pageX < 0 && this.imgMarginLeft < 0) {
          this.imgMarginLeft -= (e.pageX - this.imgScrollLeft)
        } else {
          this.imgMarginLeft += (e.pageX - this.imgScrollLeft)
        }
        if (e.pageY < 0 && this.imgMarginTop < 0) {
          this.imgMarginTop -= (e.pageY - this.imgScrollTop)
        } else {
          this.imgMarginTop += (e.pageY - this.imgScrollTop)
        }
        this.imgScrollLeft = e.pageX
        this.imgScrollTop = e.pageY
        console.log(222, this.imgScrollLeft, this.imgScrollTop)
      }
    },
    // 鼠标移出|鼠标抬起
    mouseleave() {
      if (this.mouseStatus) {
        this.mouseStatus = false
      }
    },
    // 鼠标按下
    mousedown() {
      this.mouseStatus = true
      this.boxStatus = true
    },
    // 鼠标移动(弹框拖拽)
    mousemove(e) {
      if (this.mouseStatus) {
        this.boxTop = (!this.boxStatus && this.boxTop) ? this.boxTop : e.screenY - Number(this.imgTop)
        this.boxLeft = (!this.boxStatus && this.boxLeft) ? this.boxLeft : e.screenX - Number(this.imgLeft)
        this.imgLeft = e.screenX - this.boxLeft
        this.imgTop = e.screenY - this.boxTop
        this.boxStatus = false
      }
    },
    closeViewer() {
      this.imgLeft = 500
      this.imgTop = 100
    },
    doCloseImgView() {
      this.resetVal()
      this.$emit('closeViewer')
    }
  }
}
</script>
<style lang="scss" scoped>
@import '~@/styles/mixin.scss';
.operateBtn{
  position: absolute;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-around;
  cursor: pointer;
  box-sizing: border-box;
  left: 50%;
  bottom: 40px;
  transform: translateX(-50%);
  width: 282px;
  padding: 10px 23px;
  background-color: rgba(32, 31, 31, 0.8);
  border-color: #fff;
  border-radius: 22px;
  i{
    font-size: 23px;
    color: #fff;
  }
}
.title{
  margin-left: 5px;
  font-size:16px;
  color:#222;
  line-height:22px;
  @include fontMedium;
}
.close-img{
  width:24px;
  float: right;
  cursor: pointer;
}
.previewImg{
  background:#fff;
  width: 587px;
  height: 667px;
  position: fixed;
  top: 20%;
  left: 30%;
  box-shadow:0px 2px 12px 0px rgba(0,0,0,0.1);
  border-radius:4px;
  overflow: hidden;
  padding:20px;
  z-index: 3000;
  .img-view {
    position: relative;
    left: 0;
    top: 0;
    >div{
      width: 543px;
      height: 587px;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      -webkit-app-region: no-drag
      ::-webkit-scrollbar {
        width: 0px;
        height: 10px;
        background-color: #ccc;
      }
      img{
        width: 100%;
      }
    }
  }
}
.arrowRight{
  width: 44px;
  height: 44px;
  font-size: 24px;
  color: #fff;
  background-color: #606266;
  border-color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  right: 5%;
  top: 50%;
  cursor: pointer;
}
</style>

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值