淘宝放大镜

效果图

html

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>放大镜</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html, body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }

    .wrapper {
      position: relative;
      width: 300px;
      height: 400px;
      margin: 40px;
    }

    .img-content {
      height: 400px;
      width: 300px;
    }

    .img {
      width: 300px;
      height: 400px;
      background: url("https://gd1.alicdn.com/imgextra/i4/2836027429/O1CN01XfQunw24kWqnh2pBg_!!2836027429.png_400x400.jpg") 0 0 no-repeat;
    }

    .layer {
      position: absolute;
      left: 0;
      top: 0;
      cursor: move;
      background: url("https://gtms01.alicdn.com/tps/i4/T12pdtXaldXXXXXXXX-2-2.png") repeat scroll 0 0 transparent;
      z-index: 99;
      display: none;
    }

    .preview {
      position: absolute;
      top: 0;
      left: 105%;
      height: 400px;
      width: 400px;
      border: 1px solid;
      display: none;
      overflow: hidden;
    }
  </style>
</head>
<body>
<div class="wrapper">
  <div class="img-content">
    <!-- 存放图片的容器 -->
    <div class="img"></div>
    <!-- 移动的遮罩层 -->
    <div class="layer"></div>
  </div>
  <div class="preview">
    <!-- 图片文件 -->
    <img src="./1.png" alt="">
  </div>
</div>
</body>
<!-- 引入js文件 -->
<script src="./index.js"></script>
</html>

js

在书写之前,我们需要搞清楚放大镜的原理。

鼠标移入时layer的移动操作


  如上图所示,我们需要计算出layer移动的最大的top、left和最小的top和left。同时我们还需要根据鼠标的位置计算出layer的top和left。

// 初始化layer的宽高
this.layerWidth = this.wrapper.offsetWidth / this.multiple;
this.layerHeight = this.wrapper.offsetHeight / this.multiple;
this.layer.style.width = this.layerWidth + 'px';
this.layer.style.height = this.layerHeight + 'px'// 计算layer能移动的最大位置和最小位置
let maxLeft: number = this.wrapper.offsetWidth - this.layerWidth,
    maxTop: number = this.wrapper.offsetHeight - this.layerHeight,
    minLeft: number = 0, minTop: number = 0;
let {clientX, clientY} = e;
// 取得layer的top和left
let left: number = clientX - this.wrapper.offsetLeft - this.layerWidth / 2;
let top: number = clientY - this.wrapper.offsetTop - this.layerHeight / 2;
// 对layer的top和left做临界值判断
left = (left > maxLeft) ? maxLeft : (left < minLeft ? minLeft : left);
top = (top > maxTop) ? maxTop : (top < minTop ? minTop : top);
鼠标移入时preview的显示

  在鼠标移入时,我们需要对layer所选中的区域进行放大显示,其原理即:将所显示的图片以比例放大,然后设置图片的margin。

// 图片以比例放大
img.style.width = this.multiple * this.preview.offsetWidth + 'px';
img.style.height = this.multiple * this.preview.offsetHeight + 'px';

// 设置图片的margin
img.style.marginLeft = -left * this.multiple + 'px';
img.style.marginTop = -top * this.multiple + 'px';

ts 源码

class Zoom {
  // 一些必要的dom
  private wrapper: HTMLDivElement = document.querySelector('.wrapper');
  private imgContent: HTMLDivElement = document.querySelector('.img-content');
  private layer: HTMLDivElement = document.querySelector('.layer');
  private preview: HTMLDivElement = document.querySelector('.preview');
  // layer的宽高
  private layerWidth: number;
  private layerHeight: number;
  // 放大倍数
  private readonly multiple: number;

  // 默认放大倍数是2倍
  constructor(multiple: number = 2) {
    this.multiple = multiple;
    this.initLayer();
    this.addListener()
  }
  
  // 初始化layer的宽高:根据放大比例来初始化
  private initLayer() {
    this.layerWidth = this.wrapper.offsetWidth / this.multiple;
    this.layerHeight = this.wrapper.offsetHeight / this.multiple;
    this.layer.style.width = this.layerWidth + 'px';
    this.layer.style.height = this.layerHeight + 'px'
  }

  // 添加监听
  private addListener(): void {
    // 鼠标移入,进行移动的相关操作
    this.imgContent.addEventListener('mousemove', (e: MouseEvent) => {
      this.move(e)
    });

   // 鼠标移出使preview和layer都不显示
    this.imgContent.addEventListener('mouseleave', () => {
      this.hidePreview()
          .hideLayer();
    })
  }
  // 鼠标移入的操作
  move(e: MouseEvent): void {
    // 计算layer能移动的最大位置和最小位置
    let maxLeft: number = this.wrapper.offsetWidth - this.layerWidth,
        maxTop: number = this.wrapper.offsetHeight - this.layerHeight,
        minLeft: number = 0, minTop: number = 0;
    let {clientX, clientY} = e;
    // 取得layer的top和lft
    let left: number = clientX - this.wrapper.offsetLeft - this.layerWidth / 2;
    let top: number = clientY - this.wrapper.offsetTop - this.layerHeight / 2;
    // 对layer的top和left做临界值判断
    left = (left > maxLeft) ? maxLeft : (left < minLeft ? minLeft : left);
    top = (top > maxTop) ? maxTop : (top < minTop ? minTop : top);
    // 显示layer和preivew
    this.showLayer(left, top)
        .showPreview(left, top);
  }
  
  // 根据top和left显示layer
  private showLayer(left?: number, top?: number): Zoom {
    this.layer.style.display = 'block';
    if (left && top) {
      this.layer.style.top = top + 'px';
      this.layer.style.left = left + 'px';
    }
    return this;
  }
  
  // 显示preview
  showPreview(left?: number, top?: number): Zoom {
    this.preview.style.display = 'block';
    if (left && top) {
      let previewImg: HTMLImageElement = <HTMLImageElement>this.preview.children[0];
      this.zoomImg(previewImg)
          .moveImg(previewImg, top, left);
    }
    return this;
  }
  
  // 放大显示的图片
  private zoomImg(img: HTMLImageElement): Zoom {
    img.style.width = this.multiple * this.preview.offsetWidth + 'px';
    img.style.height = this.multiple * this.preview.offsetHeight + 'px';
    return this;
  }

  // 移动图片,即设置图片的marginLeft和marginTop
  private moveImg(img: HTMLImageElement, top: number, left: number): Zoom {
    img.style.marginLeft = -left * this.multiple + 'px';
    img.style.marginTop = -top * this.multiple + 'px';
    return this;
  }
  // none掉layer
  private hideLayer(): Zoom {
    this.layer.style.display = 'none';
    return this
  }
  // none掉preview
  private hidePreview(): Zoom {
    this.preview.style.display = 'none';
    return this
  }
}


new Zoom();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值