继续我们的壁纸大战-添加放大镜效果,结尾有彩蛋

651 阅读6分钟

实现一个放大镜效果

继昨天实现了一个动态按钮组件,然后前天做了一个樱花效果自己实现一个樱花🌸落下的动态-学校的樱花开了,让我们一起去看看吧于是我离我自己的壁纸之梦越来越近了,于是今天我就开启了自己制作一个放大镜之旅。

实现放大镜的思路

简单先说一下,就是两张图片,一张图是我们刚开始看到的也就是背景图片,然后另一张图片放在一个容器里,我们使这个容器做成一个圆镜的效果,然后拖拽这个盒子,获取盒子在页面上的位置比例,然后将这个比例给容器里的图片,让容器显示图片的位置,这样就会有种效果,把盒子的区域的图片放大了。

html布局

整体布局就是我们上面讲到的,不过这里我用了视频当作背景替换图片。

  <div class="Container">
        <!-- 容器背景 -->
        <video autoplay loop>
            <!-- 嵌入视频资源,并设定视频属性 -->
            <source src="https://wallpaper-static.cheetahfun.com/wallpaper/sites/dynamics/vm8.mp4" type="video/mp4">
            <!-- 视频资源地址和格式 -->
        </video>
        <!-- 镜子 -->
        <div class="mirror">
            <video autoplay loop>
                <!-- 嵌入视频资源,并设定视频属性 -->
                <source src="https://wallpaper-static.cheetahfun.com/wallpaper/sites/dynamics/vm8.mp4" type="video/mp4">
                <!-- 视频资源地址和格式 -->
            </video>
        </div>
    </div>

css布局

在这里面我通过媒体查询自己设置了一个响应式布局,让它在不同页面下,放大镜的大小发生适配。 同时在这里需要注意的是,我把video的z-index设置成-1,这样就不会影响其他容器。然后注意的是采取,绝对定位,更方便叠加,和计算位置。

/* 重设所有元素的内边距和外边距 */
* {
    padding: 0;
    margin: 0;
  }
  
  /* 重设 body 元素的外边距和内边距 */
  body {
    margin: 0;
    padding: 0;
  }
  
  /* 设置容器元素 */
  .Container {
    /* 将容器元素的宽度设置为 100% 的视窗宽度 */
    width: 100vw;
    /* 将容器元素的高度设置为 100% 的视窗高度 */
    height: 100vh;
    /* 隐藏容器元素的滚动条 */
    overflow: hidden;
  }
  
  /* 设置视频元素 */
  .Container video {
    /* 设置视频元素的位置为固定不动 */
    position: fixed;
    /* 将视频元素固定在页面的左上角 */
    top: 0;
    left: 0;
    /* 将视频元素的宽度和高度都设置为 100% ,使其填满整个页面 */
    width: 100%;
    height: 100%;
    /* 使用 object-fit 属性将视频元素完全覆盖容器元素 */
    object-fit: cover;
    /* 设置视频元素的 z-index 属性为 -1 ,以避免video元素遮盖其他元素 */
    z-index: -1;
  }
  
  /* 设置镜子元素 */
  .mirror {
    /* 定义鼠标悬停时的光标形状 */
    cursor: pointer;
    /* 将镜子元素的宽度设置为 10% 的容器元素宽度 */
    width: 250px;
    /* 将镜子元素的高度设置为 20% 的容器元素高度 */
    height: 250px;
    /* 为镜子元素设置圆形边框 */
    border-radius: 50%;
    /* 为镜子元素设置边框,边框为 10px 粗细,颜色为白色 */
    border: solid 10px #fff;
    /* 声明镜子元素为relative布局方式 */
    position: relative;
    /* 将镜子元素相对于父元素的错位移动设置为 0 */
    left: 0;
    top: 0;
    /* 为镜子元素设置溢出隐藏 */
    overflow: hidden;
  }
  
  /* 设置镜子元素下的视频元素,这个视频元素会被实现放大镜的效果 */
  .mirror video {
    /* 将镜面图片的宽度设置为 150% 的容器元素宽度 */
    width: 150vw;
    /* 将镜面图片的高度设置为 150% 的容器元素高度 */
    height: 150vh;
    /* 将镜面图片的定位设置为绝对定位,以便实现相对于镜子元素的错位移动 */
    position: absolute;
    /* 不能使用 object-fit,而是自己通过 JS 去计算需要显示的区域,然后将视频的位置信息更新即可 */
  }

@media(max-width: 576px) {
  .mirror{
    border: solid 3px #fff;
    width: 60px;
    height: 60px;
  }
}
  

js布局

这段代码是为了实现图片放大镜效果的,通过监听鼠标在容器元素内移动事件来实现。

首先获取到了容器元素、放大镜元素以及大图元素:

const container = document.querySelector('.container')
const mirror = document.querySelector('.mirror')
const bigImg = document.querySelector('.mirror video')

随后,分别监听了鼠标进入容器范围事件、鼠标离开容器范围事件、鼠标移动事件:

container.addEventListener('mouseenter', () => {
    mirror.style.display = 'block';
});

container.addEventListener('mouseleave', () => {
    mirror.style.display = 'none';
});

container.addEventListener('mousemove', e => {
    // 计算容器元素和放大镜元素的位置、大图元素的位置
    // 具体计算方式可以看后面的注释
    // 将计算出的位置设置为对应元素的left和top值
});

当鼠标进入容器范围内时,将放大镜元素的 display 属性设置为 block,显示放大镜。

当鼠标离开容器范围后, 将放大镜元素的 display 属性设置为 none,隐藏放大镜。

当鼠标在容器元素内移动时,首先获取了鼠标在页面中的位置:

let x = e.clientX
let y = e.clientY

随后,计算出了容器元素在页面中的位置:

let left = container.offsetLeft
let top = container.offsetTop

接下来,计算出了放大镜元素在容器元素中的位置:

let mirrorLeft = x - left - mirror.offsetWidth / 2
let mirrorTop = y - top - mirror.offsetHeight / 2

通过计算得到放大镜元素在容器元素内的位置后,将其位置设置为放大镜元素的 lefttop 值。如:

mirror.style.left = mirrorLeft + 'px'
mirror.style.top = mirrorTop + 'px'

最后计算得到大图元素的位置:

let bigImgLeft = (mirrorLeft + mirror.offsetWidth / 2) / container.offsetWidth * bigImg.offsetWidth - mirror.offsetWidth / 2
let bigImgTop = (mirrorTop + mirror.offsetHeight / 2) / container.offsetHeight * bigImg.offsetHeight - mirror.offsetHeight / 2

这里的计算方法值得解释一下:

  1. 计算放大镜元素在容器元素中间的位置,这个位置是用放大镜元素的left和top值加上放大镜元素的边长的一半来计算的。(即mirrorLeft和mirrorTop)

  2. 基于放大镜元素在容器元素中的位置,将其坐标点的数值进行归一化处理,归一化后的值在0到1之间。

  3. 按照与放大镜元素在容器元素中的位置相同的比例,获得在大图中相应的位置坐标点数值,则计算此位置与左上角的偏移量。

最后将大图元素的位置设置为计算得到的位置,如:

bigImg.style.left = -bigImgLeft + 'px'
bigImg.style.top = -bigImgTop + 'px'
// 获取容器元素、放大镜元素和大图元素
const Container = document.querySelector('.Container')
const mirror = document.querySelector('.mirror')
const bigImg = document.querySelector('.mirror video')

function Mirror(){
// 监听鼠标进入容器范围事件
Container.addEventListener('mouseenter', () => {
    // 显示放大镜元素
    mirror.style.display = 'block';
});

// 监听鼠标离开容器范围事件
Container.addEventListener('mouseleave', () => {
    // 隐藏放大镜元素
    mirror.style.display = 'none';
});
function Move(e){
    let x = e.clientX
    let y = e.clientY
     //计算容器元素在页面中的位置
    let left = Container.offsetLeft
    let top = Container.offsetTop
    // 计算放大镜元素在容器元素中的位置
    let mirrorLeft = x - left - mirror.offsetWidth / 2
    let mirrorTop = y - top - mirror.offsetHeight / 2
    // 设置放大镜元素的位置
    mirror.style.left = mirrorLeft + 'px'
    mirror.style.top = mirrorTop + 'px'
    // 计算大图元素的位置
    let bigImgLeft = (mirrorLeft + mirror.offsetWidth / 2) / Container.offsetWidth * bigImg.offsetWidth - mirror.offsetWidth / 2
    let bigImgTop = (mirrorTop + mirror.offsetHeight / 2) / Container.offsetHeight * bigImg.offsetHeight - mirror.offsetHeight / 2
    // 设置大图元素的位置
    bigImg.style.left = -bigImgLeft + 'px'
    bigImg.style.top = -bigImgTop + 'px'
}
// 监听鼠标移动事件
Container.addEventListener('mousemove',Move );
Container.addEventListener('touchmove',Move );
}
Mirror()

彩蛋

目前自己制作了当前属于自己的壁纸,将樱花,放大镜,还有一个跳舞的小人,然后在网上找了一个看板娘,嘿嘿嘿!

壁纸 掘金/my_paper · Mr-W-Y-P/Html-css-js-demo - 码云 - 开源中国 (gitee.com)

放大镜 掘金/放大镜 · Mr-W-Y-P/Html-css-js-demo - 码云 - 开源中国 (gitee.com)

01.gif