Bootstrap

【JS案例】JS实现图片放大镜功能

JS案例·图片放大镜

🌟效果展示 

🌟HTML结构

🌟CSS样式

🌟实现思路  

🌟具体实现 

1.初始化数据图片

 2.获取所需DOM元素

 3.初始化页面

初始化缩略图

绑定事件

🌟完整代码

🌟写在最后 


🌟效果展示 


🌟HTML结构

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <!--最外层容器 -->
  <div class="container">
    <!-- 左侧原图 -->
    <div class="left-img">
      <!-- 遮罩层 -->
      <div class="mask"></div>
    </div>
    <!-- 右侧放大图片 -->
    <div class="right-img"></div>
    <!-- 缩略图集合 -->
    <div class="img-list-wrapper">
      <ul class="img-list">
        <li></li>
      </ul>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>

🌟CSS样式

* {
  margin: 0;
  padding: 0;
  list-style: none;
}

.container {
  width: 1000px;
  height: 600px;
  margin: 50px auto;
  font-size: 0;
}

.left-img {
  width: 490px;
  height: 510px;
  margin-right: 16px;
  border: 1px solid #eee;
  display: inline-block;
  /* 图片 */
  background-image: url(./images/imgA_2.jpg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  /* 遮罩层相对我进行定位 */
  position: relative;
}
.mask {
  width: 230px;
  height: 230px;
  background-image: url(./images/bg.png);
  position: absolute;
  top: 0;
  left: 0;
  /* opacity: 0; */
}
.right-img {
  width: 490px;
  height: 510px;
  border: 1px solid #eee;
  display: inline-block;
  background-image: url(./images/imgA_3.jpg);
  background-repeat: no-repeat;
  /* opacity: 0; */
}

.img-list-wrapper {
  width: 490px;
  text-align: center;
  margin-top: 10px;
}
.img-list {
  display: inline-block;
}
.img-list li {
  display: inline-block;
  width: 60px;
  height: 60px;
  margin: 0 5px;
  cursor: pointer;
  background-image: url(./images/imgA_1.jpg);
  background-repeat: no-repeat;
  border: 2px solid #000;
  /* border: 1px solid #eee; */
}

🌟实现思路  

在敲完上面HTML文件和CSS文件后可以看到下图效果(图片素材及完整代码文末可下载):

可以看到整体分为四块:

1. 阴影区域:其实是一张很小的像素图铺满元素形成,后续跟随鼠标移动,所选区域在右侧高清展示。

2.图片大图:就是展示的图片。

3.缩略图列表:点击切换图片。

4.高清大图展示区域。

在项目中②和③一般可以用同一种图,④会使用一张高清图。我们这里是使用三张图片来开发,缩略图,普通展示图,高清图。

因为①和④是鼠标移入才出现,所以这里 给.mask.right-img加上opacity: 0;属性如下:

接下来我们需要做的就是在鼠标移入和移出时在右侧展示与隐藏高清图,从而实现图片放大镜效果。


🌟具体实现 

1.初始化数据图片

 这里用的就是本地图片,所以先初始化数据图片,三种大小对应缩略图,展示图,高清图:

// 初始化数据图片
var imgs = {
  // 小图
  small: ['imgA_1.jpg', 'imgB_1.jpg', 'imgC_1.jpg'],
  // 中图
  middle: ['imgA_2.jpg', 'imgB_2.jpg', 'imgC_2.jpg'],
  // 大图
  large: ['imgA_3.jpg', 'imgB_3.jpg', 'imgC_3.jpg']
}

 2.获取所需DOM元素

 因为需要频繁操作DOM元素,这里简单封装一个获取DOM元素方法:

// 单一元素
function $(selector) {
  return document.querySelector(selector);
}

// 多个元素
function $$(selector) {
  return document.querySelectorAll(selector);
}

接下来获取需要用到的元素:

 3.初始化页面

初始化缩略图

初始化所有缩略图,及③区域的缩略图列表。拿到缩略图值拼接字符串,将<li></li>插入页面,并默认选中第一张缩略图:

// 初始化所有缩略图
 let str = '';
 for(var i=0; i<imgs.small.length; i++) {
   str += '<li style="background-image: url(./images/'+ imgs.small[i] +');"></li>'
 }
 smallImg.innerHTML = str
// 默认选中第一个缩略图
$('.img-list li').style.border = '2px solid #000';

绑定事件

该效果中一共有两种事件,一个是点击缩略图,另一个是鼠标移入移出。

点击缩略图切换展示图片

smallImg.onclick = function (e) {
  // 判断我点击的元素是li元素
  if (e.target.tagName == 'LI') {
    // 让所有li元素取消border
    let lis = $$('li');
    for (let i = 0; i < lis.length; i++) {
      lis[i].style.border = 'none';
    }
    // 让选中的li元素添加border
    e.target.style.border = '2px solid #000';

    // 点击缩略图后,原图和大图也需要跟着变换,
    // 点的是第几个元素, 获取元素索引
    // [1,2,3].indexOf(3) == 2
    let index = [].indexOf.call(lis, e.target);
    midImg.style.backgroundImage = 'url(./images/' + imgs.middle[index] + ')';
    largeImg.style.backgroundImage = 'url(./images/' + imgs.large[index] + ')';
  }
}

移入移出事件

这里需要计算遮罩层离边框的距离,可得到的距离有:

绿色:边框距离浏览器左边的距离

红色:鼠标距离浏览器左边的距离

黄色:遮罩层一半的距离

通过这几个值就可求出遮罩层距离边框的距离left了,同理top值一样的求法

鼠标移入

midImg.onmousemove = function (e) {
    // 让遮罩层和大图展示
    mask.style.opacity = 1;
    largeImg.style.opacity = 1;

    // 根据鼠标位置计算遮罩层的位置
    let left = e.clientX - midImg.offsetLeft - mask.offsetWidth / 2;
    // 同理
    let top = e.clientY - midImg.offsetTop - mask.offsetHeight / 2;

    // 边界条件
    if (left <= 0) {
      left = 0;
    }
    if (top <= 0) {
      top = 0;
    }
    if (left >= midImg.offsetWidth - mask.offsetWidth) {
      left = midImg.offsetWidth - mask.offsetWidth
    }
    if (top >= midImg.offsetHeight - mask.offsetHeight) {
      top = midImg.offsetHeight - mask.offsetHeight
    }
    // 根据top和left调整mask的位置
    mask.style.left = left + 'px';
    mask.style.top = top + 'px';

    // 根据top 和 left,修改大图的位置,background-position-x
    largeImg.style.backgroundPositionX = -left + 'px';
    largeImg.style.backgroundPositionY = -top + 'px';

  }

鼠标移出

  midImg.onmouseleave = function (e) {
    // 让遮罩层和大图消失
    mask.style.opacity = 0;
    largeImg.style.opacity = 0;
  }

🌟完整代码

最后在把js代码进行整理与二次封装,完整代码如下:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <!--最外层容器 -->
  <div class="container">
    <!-- 左侧原图 -->
    <div class="left-img">
      <!-- 遮罩层 -->
      <div class="mask"></div>
    </div>
    <!-- 右侧放大图片 -->
    <div class="right-img"></div>
    <!-- 缩略图集合 -->
    <div class="img-list-wrapper">
      <ul class="img-list">
      </ul>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>

index.css

* {
  margin: 0;
  padding: 0;
  list-style: none;
}

.container {
  width: 1000px;
  height: 600px;
  margin: 50px auto;
  font-size: 0;
}

.left-img {
  width: 490px;
  height: 510px;
  margin-right: 16px;
  border: 1px solid #eee;
  display: inline-block;
  /* 图片 */
  background-image: url(./images/imgA_2.jpg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  /* 遮罩层相对我进行定位 */
  position: relative;
}
.mask {
  width: 230px;
  height: 230px;
  background-image: url(./images/bg.png);
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
}
.right-img {
  width: 490px;
  height: 510px;
  border: 1px solid #eee;
  display: inline-block;
  background-image: url(./images/imgA_3.jpg);
  background-repeat: no-repeat;
  opacity: 0;
}

.img-list-wrapper {
  width: 490px;
  text-align: center;
  margin-top: 10px;
}
.img-list {
  display: inline-block;
}
.img-list li {
  display: inline-block;
  width: 60px;
  height: 60px;
  margin: 0 5px;
  cursor: pointer;
  background-image: url(./images/imgA_1.jpg);
  background-repeat: no-repeat;
  /* border: 2px solid #000; */
  border: 1px solid #eee;
}

index.js

// 封装一个获取DOM元素的方法

// 单一元素
function $(selector) {
  return document.querySelector(selector);
}

// 多个元素
function $$(selector) {
  return document.querySelectorAll(selector);
}

// 初始化数据图片
let imgs = {
  // 小图
  small: ['imgA_1.jpg', 'imgB_1.jpg', 'imgC_1.jpg'],
  // 中图
  middle: ['imgA_2.jpg', 'imgB_2.jpg', 'imgC_2.jpg'],
  // 大图
  large: ['imgA_3.jpg', 'imgB_3.jpg', 'imgC_3.jpg']
}

// 获取一些将要使用的dom元素
let container = $('.container');
let largeImg = $('.right-img');
let midImg = $('.left-img');
let smallImg = $('.img-list');
let mask = $('.mask');

// 两大类事件类型, 点击, 鼠标移入移出
// 1. 点击事件, 事件委托
smallImg.onclick = function (e) {
  // 判断我点击的元素是li元素
  if (e.target.tagName == 'LI') {
    // 让所有li元素取消border
    let lis = $$('li');
    for (let i = 0; i < lis.length; i++) {
      lis[i].style.border = 'none';
    }
    // 让选中的li元素添加border
    e.target.style.border = '2px solid #000';

    // 点击缩略图后,原图和大图也需要跟着变换,
    // 点的是第几个元素, 获取元素索引
    // [1,2,3].indexOf(3) == 2
    let index = [].indexOf.call(lis, e.target);
    midImg.style.backgroundImage = 'url(./images/' + imgs.middle[index] + ')';
    largeImg.style.backgroundImage = 'url(./images/' + imgs.large[index] + ')';
  }
}

// 函数封装,一键启动
// 函数本质:若干步骤的集合
// 初始化页面函数
function initPage() {
  var str = '';
  for (let i = 0; i < imgs.small.length; i++) {
    str += '<li style="background-image: url(./images/' + imgs.small[i] + ');"></li>'
  }
  smallImg.innerHTML = str;
  // 2. 默认选中第一个缩略图
  $('.img-list li').style.border = '2px solid #000';
}

// 绑定事件
function bindEvent() {
  midImg.onmousemove = function (e) {
    // 让遮罩层和大图展示
    mask.style.opacity = 1;
    largeImg.style.opacity = 1;

    // 根据鼠标位置计算遮罩层的位置
    let left = e.clientX - midImg.offsetLeft - mask.offsetWidth / 2;
    // 同理
    let top = e.clientY - midImg.offsetTop - mask.offsetHeight / 2;

    // 边界条件
    if (left <= 0) {
      left = 0;
    }
    if (top <= 0) {
      top = 0;
    }
    if (left >= midImg.offsetWidth - mask.offsetWidth) {
      left = midImg.offsetWidth - mask.offsetWidth
    }
    if (top >= midImg.offsetHeight - mask.offsetHeight) {
      top = midImg.offsetHeight - mask.offsetHeight
    }
    // 根据top和left调整mask的位置
    mask.style.left = left + 'px';
    mask.style.top = top + 'px';

    // 根据top 和 left,修改大图的位置,background-position-x
    largeImg.style.backgroundPositionX = -left + 'px';
    largeImg.style.backgroundPositionY = -top + 'px';

  }

  // 2. 移出
  midImg.onmouseleave = function (e) {
    // 让遮罩层和大图消失
    mask.style.opacity = 0;
    largeImg.style.opacity = 0;
  }
}

// 一键启动,执行一个函数
function main() {
  initPage();
  bindEvent();
}

main();

🌟写在最后 

本专栏将持续更新原生JS案例,提供一些工作中也能用上的一些小案例,详细讲解分析,提升JS开发水平与开发思路的积累,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以订阅一下:点击关注JS经典案例专栏

 

;