实现一个放大镜效果
继昨天实现了一个动态按钮组件,然后前天做了一个樱花效果自己实现一个樱花🌸落下的动态-学校的樱花开了,让我们一起去看看吧于是我离我自己的壁纸之梦越来越近了,于是今天我就开启了自己制作一个放大镜之旅。
实现放大镜的思路
简单先说一下,就是两张图片,一张图是我们刚开始看到的也就是背景图片,然后另一张图片放在一个容器里,我们使这个容器做成一个圆镜的效果,然后拖拽这个盒子,获取盒子在页面上的位置比例,然后将这个比例给容器里的图片,让容器显示图片的位置,这样就会有种效果,把盒子的区域的图片放大了。
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
通过计算得到放大镜元素在容器元素内的位置后,将其位置设置为放大镜元素的 left
和 top
值。如:
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
这里的计算方法值得解释一下:
-
计算放大镜元素在容器元素中间的位置,这个位置是用放大镜元素的left和top值加上放大镜元素的边长的一半来计算的。(即mirrorLeft和mirrorTop)
-
基于放大镜元素在容器元素中的位置,将其坐标点的数值进行归一化处理,归一化后的值在0到1之间。
-
按照与放大镜元素在容器元素中的位置相同的比例,获得在大图中相应的位置坐标点数值,则计算此位置与左上角的偏移量。
最后将大图元素的位置设置为计算得到的位置,如:
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)