原生js实现放大镜功能,可切换图片

放大镜主要用到的的算法性问题以及思路

移动的元素是mask和大盒子的背景图
         1.mask的移动和大盒子的背景图移动是有一定比例的
          mask的宽        小图片的宽
             --------   =   ----------    
             bigBox的宽      大图片的宽

              left    mask的宽 
             ----- =  --------
              x      bigBox的宽

            高同理
            2.mask的移动和大盒子的背景图移动是反向的

            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="style.css">
</head>

<body>
    <div class="box">
        <div class="show">
            <img src="img/1.jpg" alt="">
            <div class="mask"></div>
        </div>
        <!-- 图片列表 -->
        <ul class="list">
            <li class="active"><img src="img/1.small.jpg" alt=""></li>
            <li><img src="img/2.small.jpg" alt=""></li>
            <li><img src="img/3.small.jpg" alt=""></li>
            <li><img src="img/4.small.jpg" alt=""></li>
        </ul>
        <div class="glass">

        </div>
    </div>
</body>

</html>
<script src="amp.js"></script>
<script>
    let oBox = document.querySelector(".box");
    let arr = [{
        big: '1.jpg',
        normal: "1.jpg",
        small: '1.small.jpg',
    }, {
        big: '2.jpg',
        normal: "2.jpg",
        small: '2.small.jpg',
    }, {
        big: '3.jpg',
        normal: "3.jpg",
        small: '3.small.jpg',
    }, {
        big: '4.jpg',
        normal: "4.jpg",
        small: '4.small.jpg',
    }, ];

    let setAmplify = new Amplify(oBox, arr);
    setAmplify.init();
</script>

CSS代码:

* {
    margin: 0;
    padding: 0;
}

body {
    height: 6000px;
}

ul,
li,
ol {
    list-style: none;
}

img {
    width: 100%;
    height: 100%;
    display: block;
}

.box {
    width: 1200px;
    position: relative;
    margin: 40px auto;
    display: flex;
    flex-direction: column;
}

.box .show {
    width: 400px;
    height: 400px;
    border: 2px solid red;
    position: relative;
}

.box .show .mask {
    width: 200px;
    height: 200px;
    background: lightpink;
    opacity: .4;
    position: absolute;
    left: 0;
    top: 0;
}

.box .list {
    width: 20%;
    flex: 1;
    display: flex;
    justify-content: flex-start;
    align-items: center;
}

.box .list li {
    margin: 20px 20px 0 0;
    width: 180px;
    height: 120px;
}

.box .glass {
    width: 400px;
    height: 400px;
    border: 2px solid black;
    position: absolute;
    left: 450px;
    top: 0;
    background: url('img/1.jpg') no-repeat 0 0;
    background-size: 1600px;
}

.box .list li.active {
    border: 3px solid red;
}

JS代码:

// 放大镜封装类
// 参数1,执行放大镜效果的区域
// 参数2,是图片数据信息数组

class Amplify {
    constructor(ele, imgArray) {
        // 接收存储参数
        this.ele = ele;
        this.imgArray = imgArray;

        // 通过参数1,也就是整个放大镜区域,来获取标签对象
        // 图片区域
        this.show = ele.querySelector('.show');
        // 图片区域中的遮盖层
        this.mask = ele.querySelector('.mask');
        // 下方小图片列表中的li标签
        this.list = ele.querySelectorAll('.list li');
        // 放大镜区域
        this.glass = ele.querySelector('.glass');
        // 获取show当中的图片标签
        this.img = this.show.querySelector('img');
    }

    // 定义一个方法,来调用之后定义的所有的方法
    // 入口函数 
    init() {
        this.overOut();
        this.move();
        this.toggle();
    }

    // 鼠标的移入移出
    overOut() {
        // 鼠标移入,图片区域show,让遮盖层和放大镜显示
        this.show.addEventListener('mouseover', () => {
                this.mask.style.display = 'block';
                this.glass.style.display = 'block';
            })
            // 鼠标移出,图片区域show,让遮盖层和放大镜隐藏
        this.show.addEventListener('mouseout', () => {
            this.mask.style.display = 'none';
            this.glass.style.display = 'none';
        })
    }

    // 鼠标移动效果
    // 鼠标在 图片区域移动 时
    // 1,让遮盖层,跟随鼠标移动 --- 类似之前鼠标拖拽的效果

    move() {
        // 鼠标在show区域移动
        // 不是拖拽,没有点击事件
        // 移动出图片区域,遮盖层不显示,也不用写取消效果
        this.show.addEventListener('mousemove', (e) => {
            // 1,定位 遮盖层
            // 通过 鼠标的定位位置,来计算 遮盖层 左上角 定位的坐标位置

            // 相对于页面窗口 - div的外边距 - div的边框线 - 遮盖层宽高的一半
            // 1,如果没有页面滚动,使用相对视窗窗口 clientX 和 相对页面 PageX 是都可以的
            //   如果有页面滚动,要看放大镜部分,是否跟随页面一起运动
            //   如果一起运动,就使用 pageX
            //   如果没有一起运动,就使用 clientX
            // 2,offsetLeft , div与定位父级的间距,当前也就是与body的间距
            // 3,clientLeft , div的边框线
            // 4,遮盖层宽高的一半 , 定位之后 , 鼠标位置与遮盖层中心重合

            // 我们之前使用的获取占位,有问题,如果标签是隐藏的,无法获取占位
            // 只能使用获取宽度高度的方法
            // clientWidth  offsetHeight  获取的是占位,如果是 display:none 占位是 0
            // 只能通过获取标签css属性属性值来获取

            let x = e.pageX - this.ele.offsetLeft - this.ele.clientLeft - this.mask.clientWidth / 2;
            let y = e.pageY - this.ele.offsetTop - this.ele.clientTop - this.mask.clientHeight / 2;

            // 2,设定边界值
            // 最小是 0  最大值 父级div宽高 - 遮盖层宽高
            if (x < 0) {
                x = 0;
            }

            if (y < 0) {
                y = 0;
            }

            if (x > this.show.clientWidth - this.mask.clientWidth) {
                x = this.show.clientWidth - this.mask.clientWidth;
            }

            if (y > this.show.clientHeight - this.mask.clientHeight) {
                y = this.show.clientHeight - this.mask.clientHeight;
            }

            // 3,将数值定位给遮盖层
            this.mask.style.left = x + 'px';
            this.mask.style.top = y + 'px';

            // 4,需要让右侧放大镜的背景图片也一起移动
            // 给背景图片添加定位
            // 左侧是 图片不动,遮盖层动      遮盖层动  100  100
            // 右侧是 放大镜不动,背景图片动  背景图动 -100 -100
            // 移动时,定位必须是按照比例来设定 

            // 背景图片定位 = 背景图片大小 * 遮盖层定位 / 图片大小 
            // 通过遮盖层移动的比例,来计算,背景图片定位的数值       
            // 按照比例计算背景图片的定位
            // 背景图片定位 = 背景图片大小 * 遮盖层位移 / show的大小
            // show的大小,背景图片大小,都应该是通过JavaScript方法获取的数据
            // 可以获取宽高占位,可以是获取css样式

            let bx = 1600 * x / 400;
            let by = 1600 * y / 400;


            // 给背景图片定位
            // 给背景图片进行定位赋值操作
            // 背景图片定位:应该是 background-position : x轴定位 y轴定位
            // 使用JavaScript语法,定义 标签.style.backgroundPosition = 数值拼接px单位 数值拼接px单位
            // 使用模板字符串来解析变量
            // 也可以使用字符串拼接方式  bx + 'px' + ' ' + by + 'px'
            this.glass.style.backgroundPosition = ` -${bx}px  -${by}px `;

            // 要完美实现放大镜效果
            // 必须注意2个比例
            // 1,CSS样式的比例 :   图片区域大小 : 遮盖层大小 = 背景图片大小 : 放大镜区域大小
            // 2,定位的比例 :   遮盖层定位 : 图片区域大小 = 背景图片定位 : 背景图片大小
        })
    }

    // 切换效果
    // 1,给当前 点击click / 鼠标经过mouseover 的标签,添加样式
    //   给所有的标签去除样式,给当前点击/经过标签,添加样式

    toggle() {
        this.list.forEach((item, key) => {
            item.addEventListener('click', () => {
                // 1,给所有的li标签清除样式
                this.list.forEach((i, k) => {
                    i.className = '';
                })

                // 2,给当前的标签添加样式
                item.className = 'active';

                // 3,设定图片
                // 当前标签的索引下标 key 就是对应 图片数组中,需要显示的图片的索引下标
                // 图片的实参,存储在 this.imgArray 中 通过索引下标,可以获取到对应的图片信息
                // this.imgArray[key]
                // console.log(this.imgArray[key]);
                // 将每一个图片的具体信息,设定给图片标签和放大镜的背景图片

                // 1,给图片标签,设定路径
                // 通过数组,索引,图片属性,获取对应的图片名称
                // 标签.src = 赋值   或者  标签.setAttribute('src' , 属性值) 都可以
                // this.img.src = `./images/${this.imgArray[key]['normal']}`;
                this.img.setAttribute('src', `./img/${this.imgArray[key]['normal']}`);

                // 2,给放大镜区域,背景图片设定路径
                // 必须把关于背景图片的所有设定都重新写一遍
                this.glass.style.background = `url('./img/${this.imgArray[key]['big']}') no-repeat 0 0`;
                this.glass.style.backgroundSize = '1600px';
            })
        })
    }


}

 

posted @ 2022-01-15 16:04  thomas_001  阅读(493)  评论(0)    收藏  举报