简易 图片浏览 组件

根据业务做了一个简易图片浏览组件,分享一下

<template>
  <div class="content-box">
    <p class="switch-button switch-pre" @click="pre"><i class="el-icon-arrow-left"></i></p>
    <p class="switch-button switch-next" @click="next"><i class="el-icon-arrow-right"></i></p>
    <ul v-if="imgUrl" class="operation-box">
      <li class="operation-button operation-grow" @click="grow">
        <i class="el-icon-zoom-in"></i>
      </li>
      <li class="operation-button operation-shrink" @click="shrink">
        <i class="el-icon-zoom-out"></i>
      </li>
      <li class="operation-button operation-tranform" @click="clockwise">
        <i class="el-icon-refresh-right"></i>
      </li>
      <li class="operation-button operation-tranform" @click="contrarotate">
        <i class="el-icon-refresh-left"></i>
      </li>
    </ul>
    <ul class="switch-dot-box">
      <li v-for="(item,i) in this.imgs" :class="['switch-dot',{'switch-dot_now':index === i}]" :key="i+'img-preview'"></li>
    </ul>
    <div class="images-box" ref="imgBox">
      <!-- draggable="false" -->
      <img v-if="imgUrl" class="images-box_img" :src="imgUrl" ref="img" ondragstart="return false;" @mousedown.stop="mouseDown">
      <div v-else class="img-error">
        <i class="el-icon-picture-outline"></i>
      </div>
    </div>
  </div>
</template>

<script>
import { calculator } from '@/util'
const getStyle = (obj, attr) => {
  if (obj.currentStyle) {
    return obj.currentStyle[attr]
  } else {
    return getComputedStyle(obj, null)[attr]
  }
}
export default {
  name: 'img-preview',
  props: {
    imgs: {
      type: Array,
      require: true
    }
  },
  data () {
    return {
      // 图片伸缩值
      flexValue: 1,
      // 图片伸缩最小值
      flexMin: 0.5,
      // 图片伸缩最大值
      flexMax: 3,
      // 图片伸缩比例
      flexProp: 0.2,
      // z轴旋转值
      rotateZ: 0,
      imgUrl: '',
      index: 0,
      isPress: false,
      //   鼠标移动的距离
      disX: 0,
      disY: 0,
      //   鼠标坐标
      clientX: 0,
      clientY: 0
    }
  },
  methods: {
    contrarotate () {
      this.flexValue = 1
      if (this.rotateZ === 0) this.rotateZ = 270
      else this.rotateZ = calculator.sub(this.rotateZ, 90)
      this.transform()
      this.$refs.img.style.setProperty('left', '0px')
      this.$refs.img.style.setProperty('top', '0px')
    },
    clockwise () {
      this.flexValue = 1
      if (this.rotateZ === 270) this.rotateZ = 0
      else this.rotateZ = calculator.add(this.rotateZ, 90)
      this.transform()
      this.$refs.img.style.setProperty('left', '0px')
      this.$refs.img.style.setProperty('top', '0px')
    },
    grow () {
      if (this.flexValue < this.flexMax) {
        this.flexValue = calculator.add(this.flexValue, this.flexProp)
        this.transform()
      }
    },
    shrink () {
      if (this.flexValue > this.flexMin) {
        this.flexValue = calculator.sub(this.flexValue, this.flexProp)
        this.transform()
      }
    },
    transform () {
      this.$refs.img.style.setProperty('transform', `rotateZ(${this.rotateZ}deg) scale(${this.flexValue})`)
    },
    pre () {
      if (this.index === 0) {
        this.index = this.imgs.length - 1
      } else {
        this.index = this.index - 1
      }
      this.flexValue = 1
      this.imgUrl = this.imgs[this.index]
    },
    next () {
      if (this.index === this.imgs.length - 1) {
        this.index = 0
      } else {
        this.index = this.index + 1
      }
      this.flexValue = 1
      this.imgUrl = this.imgs[this.index]
    },
    mouseDown (e) {
      const that = this
      const width = this.$refs.imgBox.clientWidth
      const height = this.$refs.imgBox.clientHeight
      const initX = parseInt(getStyle(this.$refs.img, 'left'))
      const initY = parseInt(getStyle(this.$refs.img, 'top'))
      const disX = e.clientX
      const disY = e.clientY
      document.onmousemove = (env) => {
        // 鼠标移动的距离
        let x = env.clientX - disX + initX
        let y = env.clientY - disY + initY
        // 设置边界 图片放大最多3倍
        if (x < calculator.sub(100, calculator.mul(width, that.flexValue))) x = calculator.sub(100, calculator.mul(width, that.flexValue))
        if (x > calculator.sub(calculator.mul(width, that.flexValue), 100)) x = calculator.sub(calculator.mul(width, that.flexValue), 100)
        if (y < calculator.sub(100, calculator.mul(height, that.flexValue))) y = calculator.sub(100, calculator.mul(height, that.flexValue))
        if (y > calculator.sub(calculator.mul(height, that.flexValue), 100)) y = calculator.sub(calculator.mul(height, that.flexValue), 100)
        this.$refs.img.style.setProperty('left', `${x}px`)
        this.$refs.img.style.setProperty('top', `${y}px`)
      }
      // 图形移出父盒子取消移动事件,防止移动过快触发鼠标移出事件,导致鼠标弹起事件失效
      this.$refs.imgBox.onmouseleave = () => {
        document.onmousemove = null
        document.onmouseup = null
      }
      // 鼠标弹起后停止移动
      document.onmouseup = () => {
        document.onmousemove = null
        document.onmouseup = null
      }
      // 阻止冒泡
      return false
    }
  },
  created () {
    this.imgUrl = this.imgs[this.index]
  },
  watch: {
    index: {
      handler () {
        if (this.imgUrl) {
          this.flexValue = 1
          this.rotateZ = 0
          this.transform()
          this.$refs.img.style.setProperty('top', `${0}px`)
          this.$refs.img.style.setProperty('left', `${0}px`)
        }
      },
      deep: true
    }
  }
}
</script>

<style lang="scss" scoped>
.content-box {
  width: 100%;
  height: 100%;
  position: relative;
  border: 1px solid coral;
}
.switch-button {
  position: absolute;
  top: 50%;
  font-size: 30px;
  transform: translateY(-50%);
  cursor: pointer;
  z-index: 1000;
  font-size: 50px;
  opacity: 0.5;
}
.switch-pre {
  left: 3px;
}
.switch-next {
  right: 3px;
}
.operation-box {
  position: absolute;
  top: 20px;
  left: 30px;
  width: 150px;
  background: rgba(255, 255, 255, 0.5);
  display: flex;
  justify-content: space-around;
}
.operation-button {
  font-size: 30px;
  font-weight: 700;
  padding: 1px;
  border-radius: 50%;
  cursor: pointer;
  z-index: 1000;
  color: #000;
}
.images-box {
  box-sizing: content-box;
  margin: 1px;
  width: calc(100% - 2px);
  height: calc(100% - 2px);
  overflow: hidden;
  position: relative;
  background: #f4f5f6;
}
.images-box_img {
  transform-origin: center center;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  cursor: move;
}
.img-error {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.switch-dot-box {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  padding: 5px;
  display: flex;
  z-index: 1000;
}
.switch-dot {
  width: 10px;
  height: 10px;
  background: cyan;
  border-color: cyan;
  border-radius: 50%;
  margin: 0 10px;
  z-index: 1000;
  transition-duration: 0.8s;
}
.switch-dot.switch-dot_now {
  transform: scale(1.5);
}
</style>

效果图

calculator 是一个封装的加减乘除方法

const calculator = {
  add (num1 = 0, num2 = 0, d) {
    const s1 = num1.toString()
    const s2 = num2.toString()
    const s1Arr = s1.split('.')
    const s2Arr = s2.split('.')
    // eslint-disable-next-line eqeqeq
    const d1 = s1Arr.length == 2 ? s1Arr[1] : ''
    // eslint-disable-next-line eqeqeq
    const d2 = s2Arr.length == 2 ? s2Arr[1] : ''
    const maxLen = Math.max(d1.length, d2.length)
    const m = Math.pow(10, maxLen)
    const result = Number(tofixed(((num1 * m + num2 * m) / m), maxLen))
    return typeof d === 'number' ? Number(tofixed(result, d)) : result
  },

  sub (num1, num2, d) {
    return calculator.add(num1, -Number(num2), d)
  },

  mul (num1 = 0, num2 = 0, d) {
    const s1 = num1.toString()
    const s2 = num2.toString()
    const m =
      (s1.split('.')[1] ? s1.split('.')[1].length : 0) +
      (s2.split('.')[1] ? s2.split('.')[1].length : 0)
    const resultVal =
      (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) /
      Math.pow(10, m)
    return typeof d !== 'number'
      ? Number(resultVal)
      : Number(tofixed(resultVal, parseInt(d)))
  },

  div (num1, num2, d) {
    const s1 = num1.toString()
    const s2 = num2.toString()
    const m =
      (s2.split('.')[1] ? s2.split('.')[1].length : 0) -
      (s1.split('.')[1] ? s1.split('.')[1].length : 0)
    let resultVal =
      (Number(s1.replace('.', '')) / Number(s2.replace('.', ''))) *
      Math.pow(10, m)
    resultVal = resultVal || 0
    return typeof d !== 'number'
      ? Number(resultVal)
      : Number(tofixed(resultVal, parseInt(d)))
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值