vue中手写一个放大镜功能

vue中手写一个放大镜功能

有的时候需要对图片进行放大,类似于电商的商品放大功能,于是在这个想法上写了一个放大镜的功能,并且在放大镜的基础上新添加了一些小功能,下面开始吧!

放大镜是封装的组件的形式,用的时候只需要传入图片,和放大倍数的图片即可。

首先前提写了一个监听屏幕大小然后改变图片大小的功能,不让图片超出屏幕的大小;

需要安装一个插件element-resize-detector-- “^1.2.1”

	let _this = this; //this重定向
    var elementResizeDetectorMaker = require("element-resize-detector");
    // 创建实例
    var erd = elementResizeDetectorMaker();
    // 创建实例带参
    elementResizeDetectorMaker({
      strategy: "scroll",
      callOnAdd: true,
      debug: true
    });
    //监听id为pic-img的元素 大小变化
    erd.listenTo(document.getElementById("pic-img"), function(element) {
      var width = element.offsetWidth; //容器宽
      var height = element.offsetHeight; //容器高
      _this.divSize = { x: width, y: height };
    });

然后就是放大镜的功能,废话少说,直接上全部代码

<template>
  <div class="img">
    <div class="pic-img" id="pic-img">
      <div
        class="img-container"
        style="width: 1000px"
        @mousemove="!moveEvent && mouseMove($event)"
        @mouseleave="!leaveEvent && mouseLeave($event)"
        :style="imgStyle"
      >
        <img ref="img" :src="url" />
        <!-- 图片内部盒子 -->
        <div
          v-show="xixi"
          v-if="!hideZoom&&imgLoadedFlag"
          :class="['img-selector', { circle: type === 'circle' }]"
          :style="[
                imgSelectorSize,
                imgSelectorPosition,
                !outShow && imgSelectorBg,
                !outShow && imgBgPosition,
              ]"
        ></div>
      </div>
      <!-- 图片外部盒子 -->
      <div
        v-if="outShow"
        v-show="!hideOutShow"
        class="img-out-show"
        :style="[imgOutShowSize, imgSelectorBg, imgBgPosition]"
      ></div>
    </div>
    <div class="option_img">
      <div class="operation">
        <img v-show="allshow" @click="eye(0)" src="./img//open.png" alt title="显示放大" />
        <img v-show="!allshow" @click="eye(1)" src="./img//zoom in_no.png" alt title="不显示放大" />

        <img src="./img/inside.png" alt v-show="part" @click="mode(0)" title="内部放大" />
        <img src="./img//outer.png" alt v-show="!part" @click="mode(1)" title="外部放大" />
        <p @click="magnification">
          <span>×{{ multiple }}</span>
        </p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "vue-photo-zoom-pro",
  data() {
    return {
      //全显全不显
      classData: {
        type: 1,
        id: 100
      },
      fourShow: false,
      allshow: true,
      part: true, //内部放大还是外部放大
      multiple: 2, //倍数
      num: 0, //记录题目
      xixi: false,
      hideZoom: false,
      scale: 2,
      divSize: {},
      imgSize: {}, //记录图片的大小
      outShow: false,

      selector: {
        width: 166, //图片上面覆盖框大小
        halfWidth: 83,
        top: 0,
        left: 0,
        bgTop: 0,
        bgLeft: 0,
        rightBound: 0,
        bottomBound: 0,
        absoluteLeft: 0,
        absoluteTop: 0
      },
      imgInfo: {},
      hideOutShow: true,
      imgLoadedFlag: true, //用来判断图片加载
      screenWidth: document.body.clientWidth,
      timer: null
    };
  },
  props: {
    url: {
      type: String
    },
    highUrl: {
      type: String
    },
    type: {
      type: String,
      default: "square",
      validator: function(value) {
        return ["circle", "square"].indexOf(value) !== -1;
      }
    },
    moveEvent: {
      type: [Object, MouseEvent],
      default: null
    },
    leaveEvent: {
      type: [Object, MouseEvent],
      default: null
    }
  },
  watch: {
    moveEvent(e) {
      this.mouseMove(e);
    },
    leaveEvent(e) {
      this.mouseLeave(e);
    },
    url() {
      this.imgLoadedFlag = true;
    }
  },
  computed: {
    //定义图片大小
    imgStyle() {
      var w, h;
      var imgK = this.imgSize.width / this.imgSize.height;
      var boxK = this.divSize.x / this.divSize.y;
      if (imgK > boxK) {
        if (this.imgSize.width > this.divSize.x) {
          w = this.divSize.x;
          h = parseInt(
            (this.divSize.x / this.imgSize.width) * this.imgSize.height
          );
        } else if (this.imgSize.width < this.divSize.x) {
          w = this.imgSize.width;
          h = this.imgSize.height;
        }
      } else if (imgK < boxK) {
        if (this.imgSize.height > this.divSize.y) {
          h = this.divSize.y;
          w = parseInt(
            (this.divSize.y / this.imgSize.height) * this.imgSize.width
          );
        } else if (this.imgSize.height < this.divSize.y) {
          w = this.imgSize.width;
          h = this.imgSize.height;
        }
      }
      return `width:${w}px;height:${h}px`;
    },

    imgSelectorPosition() {
      let { top, left } = this.selector;
      return {
        top: `${top}px`,
        left: `${left}px`
      };
    },
    imgSelectorSize() {
      let width = this.selector.width;
      return {
        width: `${width}px`,
        height: `${width}px`
      };
    },
    imgOutShowSize() {
      let {
        selector: { width }
      } = this;
      return {
        width: `${width * this.multiple}px`,
        height: `${width * this.multiple}px`
      };
    },
    imgSelectorBg() {
      let {
        scale,
        imgInfo: { height, width }
      } = this;
      return {
        backgroundImage: `url(${this.highUrl || this.url})`,
        backgroundSize: `${width * scale}px ${height * scale}px`
      };
    },
    imgBgPosition() {
      let { bgLeft, bgTop } = this.selector;
      return {
        backgroundPosition: `${bgLeft}px ${bgTop}px`
      };
    }
  },
  mounted() {
    let _this = this; //this重定向
    var elementResizeDetectorMaker = require("element-resize-detector");
    // 创建实例
    var erd = elementResizeDetectorMaker();
    // 创建实例带参
    elementResizeDetectorMaker({
      strategy: "scroll",
      callOnAdd: true,
      debug: true
    });
    //监听id为pic-img的元素 大小变化
    erd.listenTo(document.getElementById("pic-img"), function(element) {
      var width = element.offsetWidth; //容器宽
      var height = element.offsetHeight; //容器高
      _this.divSize = { x: width, y: height };
    });
  },
  methods: {
    //全显全不显
    eye(val) {
      if (val) {
        this.allshow = true;
        this.hideZoom = false;
      } else {
        this.allshow = false;
        this.hideZoom = true;
      }
    },

    mode(val) {
      //内部放大还是外部放大
      if (val) {
        this.part = true;
        this.outShow = false;
      } else {
        this.part = false;
        this.outShow = true;
      }
    },
    magnification() {
      if (this.multiple < 3) {
        this.multiple++;
        this.scale = this.multiple;
      } else {
        this.multiple = 2;
        this.scale = this.multiple;
      }
    },

    imgLoaded() {
      let imgInfo = this.$refs["img"].getBoundingClientRect();
      if (JSON.stringify(this.imgInfo) == JSON.stringify(imgInfo)) {
        // 位置不变不更新
        return;
      }
      this.imgLoadedFlag = true;
      let { width, height, left, top } = (this.imgInfo = imgInfo);
      let selector = this.selector;
      let { width: selectorWidth, halfWidth: selectorHalfWidth } = selector;
      let { scrollLeft, scrollTop } = document.documentElement;
      selector.rightBound = width - selectorWidth;
      selector.bottomBound = height - selectorWidth;
      selector.absoluteLeft = left + selectorHalfWidth + scrollLeft;
      selector.absoluteTop = top + selectorHalfWidth + scrollTop;
    },
    reset() {
      Object.assign(this.selector, {
        top: 0,
        left: 0,
        bgLeft: 0,
        bgTop: 0
      });
    },
    mouseMove(e) {
      this.xixi = true;
      if (!this.hideZoom && this.imgLoadedFlag) {
        this.imgLoaded(); //防止img位置变化
        let { pageX, pageY } = e;
        let { scale, selector } = this;
        let {
          halfWidth,
          absoluteLeft,
          absoluteTop,
          rightBound,
          bottomBound
        } = selector;
        let x = pageX - absoluteLeft; // 选择器的x坐标 相对于图片
        let y = pageY - absoluteTop; // 选择器的y坐标
        if (this.outShow) {
          halfWidth = 0;
          this.hideOutShow = false;
        }
        selector.top = y > 0 ? (y < bottomBound ? y : bottomBound) : 0;
        selector.left = x > 0 ? (x < rightBound ? x : rightBound) : 0;
        selector.bgLeft = halfWidth - (halfWidth + x) * scale; // 选择器图片的坐标位置
        selector.bgTop = halfWidth - (halfWidth + y) * scale;
      }
    },
    mouseLeave() {
      if (this.outShow) {
        this.hideOutShow = true;
      }
      this.xixi = false;
    }
  }
};
</script>

<style scoped>
.img {
  width: 70%;
  height: 100%;
  float: left;
}
.pic-img {
  width: 100%;
  height: 85%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #eee;
  box-shadow: 0 0 5px #ccc;
}
.option_img {
  width: 100%;
  height: 90px;
  background: linear-gradient(180deg, #fdfdfd 0%, #e2e2e2 86%, #f7f6f6 100%);
  border: 1px solid #d9d9d9;
}
.operation {
  width: 360px;
  height: 70px;
  margin: 10px auto;
  position: relative;
  background-size: 100% 100%;
}
.operation input {
  width: 50px;
  height: 50px;
  border: none;
  border-radius: 50%;
}
.operation > p {
  width: 70px;
  height: 70px;
  line-height: 40px;
  font-size: 28px;
  color: #7dc5eb;
  cursor: pointer;
  float: left;
  margin-top: 2px;
}
.operation > p > span {
  display: inline-block;
  border-radius: 50%;
  margin-top: 7px;
  width: 40px;
  height: 40px;
  border: 3px solid #038cf4;
  color: #038cf4;
}
.operation > img {
  width: 70px;
  height: 70px;
  float: left;
  cursor: pointer;
  float: left;
  margin-left: 2px;
  margin-top: 2px;
}

.img-container {
  position: relative;
}
.img-container > img {
  /* image-orientation: 0deg; */
  /* image-orientation: none; */
}
.img-selector {
  background-color: rgba(0, 0, 0, 0.6);
  position: absolute;
  background-repeat: no-repeat;
  pointer-events: none;
  cursor: move;
  border: 1px solid rgba(0, 0, 0, 0.1);
  z-index: 99;
  /* display: none; */
}

.img-selector.circle {
  border-radius: 50%;
}

.img-out-show {
  position: absolute;
  bottom: 0;
  right: 0;
  background-repeat: no-repeat;
  transform: translate(100%, 0);
  border: 1px solid rgba(0, 0, 0, 0.1);
}

img {
  width: 100%;
  height: 100%;
}
</style>

最后父组件引用的时候:

<template>
  <div id="app">
    <HelloWorld :url="url" :highUrl="highUrl"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
    return{
      url:require("./components/img/2.jpg"),
      highUrl: require("./components/img/2.jpg"),
    }
  },
  components: {
    HelloWorld
  }
}
</script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值