天天看点

放大镜效果放大镜效果

放大镜效果

这里的放大镜效果是指当鼠标(手指)和页面(屏幕)中一个方框内的图片交互时,图片呈现放大效果,图片在框内显示的放大区域随鼠标(页面)位置的改变而改变

放大镜效果放大镜效果

演示链接:https://codesandbox.io/s/fangdajingxiaoguo-jxdfo

源码:https://gitee.com/thisismyaddress/webpage-effects/tree/master/magnifier-effect

以下我尝试了几种不同的实现方式

移动图片框内的图片

这里是通过改变图片框内的一张图片的大小和绝对定位偏移量实现最终效果

HTML的基本结构如下:

<div id="image">
    <!-- 该图片设置为绝对定位 -->
    <img src="./img/doge.webp" alt="doge">
</div>
           

这里JS中涉及到的事件有

mouseenter

mouseleave

mousemove

,这些事件都和图片框绑定(

imageBox

mouseenter

事件处理函数中,只需要将框中的图片尺寸放大即可:

imageBox.addEventListener('mouseenter', () => {
   	// 这里将图片(图片和框一样为正方形)放大为 450x450 ,相当于图片框的3倍(150x150)
    img.style.width = '450px';
})
           

mouseleave

事件处理函数中则只需要将定位偏移的样式和图片放大尺寸样式清除即可:

// 清除所有样式 >> 恢复原样
imageBox.addEventListener('mouseleave', () => {
    img.style.width = '';
    img.style.top = '';
    img.style.left = '';
})
           

图片的放大效果的实现重点是

mousemove

的事件处理函数中关于图片定位偏移量的计算

这里的思路是找出当前鼠标位置相对于图片框左上角的坐标位置

x, y

,接着计算出这个坐标位置在图片框中的相对百分比位置(比如该点在框的正中间的话就是

0.5, 0.5

或者

50%, 50%

的位置,这个百分比是相对于框体的左上角而言的),利用这个百分比位置在放大的图片中找到相同的相对位置下,图片中的这个目标点的具体坐标位置

targetX, targetY

,然后将

x, y

targetX, targetY

这两个点通过定位偏移重叠即可,这就要求出这两个点的水平偏移距离和垂直偏移距离

distanceX, distanceY

,由于需要将图片相对于图片框的进行绝对定位偏移,那么就需要进行反向偏移,则需要对求出的

distanceX, distanceY

取负值,也就是最终的定位偏移为

left: - distanceX + 'px'; top: - distanceY + 'px'

以下为需要求出的量的具体计算:

  • 当前鼠标位置相对于图片框左上角的坐标

    x, y

    鼠标在页面中的具体位置可以通过

    e.pageX, e.pageY

    获得(

    e

    表示鼠标事件对象),这个具体位置是相对于页面的左上角计算的,那么相对于框体的左上角位置,可以通过减去框体的顶边和左边距离页面的顶边和左边的距离(也就是

    imageBox.offsetTop, imageBox.offsetLeft

    )获得:
    x = e.pageX - imageBox.offsetLeft;
    y = e.pageY - imageBox.offsetTop;
               
  • 坐标在图片框中的相对百分比位置:

    相对于整个框体的相对位置的计算需要使用到框体的高度和宽度(

    imageBox.offsetWidth, imageBox.offsetHeight

    x / imageBox.offsetWidth;
    y / imageBox.offsetHeight;
               
  • 放大的图片中相同相对位置下的目标点

    targetX, targetY

    :

    这需要利用到上述计算得到的相对位置,再去乘以放大的图片的尺寸(

    img.offsetWidth, img.offsetHeight

    )获得
    targetX = img.offsetWidth * x / imageBox.offsetWidth;
    targetY = img.offsetHeight * y / imageBox.offsetHeight;
               
  • 需要进行偏移的距离

    distanceX, distanceY

    :

    偏移的水平距离和垂直距离就是上述两个相对位置

    x, y

    targetX, targetY

    的水平距离和垂直距离的差值:
    distanceX = targetX - x;
    distanceY = targetY - y;
               
  • 将图片相对于图片框进行绝对定位偏移,需要将图片反向移动,所以需要对偏移距离的值取负:
    img.style.left = - distanceX + 'px';
    img.style.top = - distanceY + 'px';
               

至此对于图片定位偏移量的计算就结束了(具体计算可以参见下图解析)

放大镜效果放大镜效果

所以最终的

mousemove

的事件处理函数为:

imageBox.addEventListener('mousemove', (e) => {
    // 当前鼠标位置相对于图片框左上角的坐标x, y
    let x = e.pageX - imageBox.offsetLeft;
    let y = e.pageY - imageBox.offsetTop;
    // 放大的图片中相同相对位置下的目标点targetX, targetY
    let targetX = img.offsetWidth * x / imageBox.offsetWidth;
    let targetY = img.offsetHeight * y / imageBox.offsetHeight;
    // 需要进行偏移的距离distanceX, distanceY
    let distanceX = targetX - x;
    let distanceY = targetY - y;
    // 将图片相对于图片框进行绝对定位偏移,需要将图片反向移动,所以需要对偏移距离的值取负
    img.style.left = - distanceX + 'px';
    img.style.top = - distanceY + 'px';
})
           

移动图片框的背景图片

这里将上述的图片框内的图片移除,直接将要放大的图片作为图片框的背景图片,通过改变背景图片大小和背景图片位置来实现最终效果

HTML的基本结构如下:

这里涉及到的三个JS事件还是

mouseenter

mouseleave

mousemove

,这些事件都和图片框绑定(

imageBox

mouseenter

事件处理函数中,只需要将框的背景图片尺寸放大即可:

image.addEventListener('mouseenter', (e) => {
    // image.style.backgroundSize = '450px';
    e.target.style.backgroundSize = '450px';
});
           

mouseleave

事件处理函数中则是只需要将背景图片的尺寸和位置样式清除即可:

image.addEventListener('mouseleave', (e) => {
    // image.style.backgroundSize = '';
    // image.style.backgroundPosition = '';
    e.target.style.backgroundSize = '';
    e.target.style.backgroundPosition = '';
});
           

这里的实现重点依然是对图片偏移量的计算,不过不一样的是,这里的背景图片尺寸信息比较难找到相关属性值来动态获取,不能像上述采用绝对定位的做法那样求出具体的偏移距离。而如果设为定值,那么当背景图片的放大尺寸变了,程序要改的地方就比较多了

这里利用背景图片位置的百分比取值来实现将图片移动到目标位置的目的(这样甚至都不用计算具体偏移距离了)

这里简单讲一下背景图片位置

background-position

取值为百分数时的表现:

百分比值的偏移指定图片的相对位置和容器的相对位置重合,执行的是下述公式

(container width - image width) * (position x%) = (x offset value)
(container height - image height) * (position y%) = (y offset value)
参考:https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-position
           

从上述公式可以看出当背景图片大小和容器大小相同时,使用百分比取值是不会有偏移的

其实百分比取值的表现说白了就是指定一个相对于图片左上角的一个相对位置,这个位置会和容器相对于左上角的相同的相对位置重叠,比如

background-position: 50% 50%

,这个点指定的是背景图片的正中心,那么此时该取值会使背景图片的正中心和容器的正中心重合

回归正题,此时采用背景图片位置的百分比取值,则只需要计算出当前鼠标位置相对于图片框左上角的坐标

x, y

在图片框中的相对百分比位置,就可以实现背景图片的正确偏移

放大镜效果放大镜效果
image.addEventListener('mousemove', (e) => {
    // let x = e.pageX - image.offsetLeft;
    // let y = e.pageY - image.offsetTop;
    // // 偏移百分比
    // let xOffset = x / image.offsetWidth * 100;
    // let yOffset = y / image.offsetHeight * 100;

    // image.style.backgroundPosition = xOffset + '% ' + yOffset + '%';

    // 计算出鼠标当前相对于图片框左上角的坐标
    let x = e.pageX - e.target.offsetLeft;
    let y = e.pageY - e.target.offsetTop;

    // 计算出相对位置
    // 乘 100 是为了转成百分数的大小
    let xOffset = x / e.target.offsetWidth * 100;
    let yOffset = y / e.target.offsetHeight * 100;

    e.target.style.backgroundPosition = xOffset + '% ' + yOffset + '%';
});
           

移动图片框的背景图片——使用尽可能多的CSS特性

这里主要是我看了B站的一个视频教程后的一个尝试,虽然其中的步骤略显繁杂,但在对其实现的过程让我学习到了新的知识

这里的实现使用了尽可能多的CSS特性,另外还尝试了未曾用过的API(

getBoundingClientRect()

e.offsetX

e.offsetY

这里依然使用移动背景图片的方式,涉及到的JS事件还是

mouseenter

mouseleave

mousemove

(都和图片框绑定)

mouseenter

中放大图片的操作不再是直接放大背景图片,而是通过添加属性的方式间接实现:

这里为图片框设置一个

zoomed="1"

的属性,来表示此时处于放大状态,这样的话需要配合CSS选择器来改变背景图片尺寸:

#image[zoomed] {
    background-size: 450px auto;
}
           
image.addEventListener('mouseenter', (e) => {
    e.target.setAttribute('zoomed', 1);
})
           

当鼠标离开时需要图片缩小,那么只需要移除属性即可:

image.addEventListener('mouseleave', (e) => {
	e.target.removeAttribute('zoomed');
});
           
放大镜效果放大镜效果

接下来在

mousemove

实践处理函数中还是通过改变背景图片位置的百分比取值实现图片位置的偏移,但这里不直接改变背景图片位置的样式,而是通过改变两个CSS属性(

--x

--y

)来间接改变图片位置样式。并且图片框尺寸是通过

getBoundingClientRect()

返回的一个对象的

width

height

属性获取。另外当前鼠标位置相对于框体左上角的坐标位置不再需要特地进行计算获得,而是直接使用

e.offsetX

e.offsetY

,这两个属性表示的就是相对于框体左上角计算的鼠标位置

image.addEventListener('mousemove', moveHandler(e) {
    // 这里特地尝试使用了 getBoundingClientRect()
    // 这里不作解释,只要知道它可以方法返回元素的大小及其相对于视口的位置即可
    let rect = e.target.getBoundingClientRect();

	// 这里的 e.offsetX 和 e.offsetY 表示的是鼠标相对于框体左上角的位置,相当于上述特地计算的 x 和 y
	// rect.width 相当于 e.target.offsetWidth ,rect.height 相当于 e.target.offsetHeight
    let xOffset = e.offsetX / rect.width;
    let yOffset = e.offsetY / rect.height;

	// 通过改变两个CSS属性(--x和--y)来间接改变图片位置样式
    e.target.style.setProperty('--x', xOffset);
    e.target.style.setProperty('--y', yOffset);
});
           

上述事件处理函数中最后设置了两个CSS变量的值,这时应该使用起来,使其生效:

#image[zoomed] {
    background-size: 450px auto;
    /* 将 --x 和 --y 通过 var() 解析出计算值并应用到背景图片位置样式中 */
    background-position: calc(var(--x) * 100%) calc(var(--y) * 100%);
}
           

尝试兼容移动端

上述的应用都是在PC端下的,是无法在移动端使用的,因为移动端下并没有鼠标事件,所以上述的事件都不会触发,自然的,放大镜的效果就无法实现了

在移动端下需要使用触摸事件来实现这个效果,这里涉及到的触摸事件有

touchstart

touchend

touchmove

,这些事件都和图片框绑定。在具体实现上的思路和上述一致:触摸开始(

touchstart

)时图片放大,触摸结束(

touchend

)时图片恢复原来大小并清除图片偏移样式,触摸点移动时(

touchmove

)需要计算图片的偏移。只是在具体实现上需要进行一些编码调整

这里采用移动背景图片的方式(使用移动图片框内图片的方式大同小异,只是在计算偏移量方面的计算量会大一点),并且是对上面的那个使用了尽可能多的CSS属性的做法进行的移动端兼容

touchstart

touchend

的事件处理函数的内容可以和上述

mouseenter

mouseleave

的分别一样:

image.addEventListener('touchstart', (e) => {
    e.target.setAttribute('zoomed', 1);
});

image.addEventListener('touchend', (e) => {
    e.target.removeAttribute('zoomed');
});
           

这里差异较大的地方在于

touchmove

的事件处理函数内容。

  • 由于触发触摸事件的触摸点可能不止一个(多个手指触摸屏幕),所以这里在进行计算时需要特别的指明一个触摸点,使用

    e.touches[0]

    而不是

    e

    指定一个触摸事件对象,避免出现混乱,那么触摸事件源可以通过

    e.touches[0].target

    获得
  • 由于触摸事件对象并没有

    e.offsetX

    e.offsetY

    这两个属性,所以触摸点位置相对于框体左上角的坐标依然需要特地进行计算。这里由于需要特地的去尝试

    getBoundingClientRect()

    ,在计算过程中为了获取框体的位置信息,使用该方法返回的对象的

    top

    left

    属性获得,并且要注意:该方法返回的框体位置信息是相对于视口而不是相对于页面而言的,所以如果页面发生滚动时,使用相对于页面计算的触摸点位置属性

    pageX

    pageY

    计算出的结果是不准确,这里应该采用同样相对于视口计算的触摸点位置属性

    clientX

    clientY

    // 使用相对于视口计算的触摸点位置 clientX 和 clientY
    // rect = e.target.getBoundingClientRect()
    x = e.touches[0].clientX - rect.left;
    y = e.touches[0].clientY - rect.top;
    
    // 如果要使用相对于页面计算的触摸点位置 pageX 和 pageY,
    // 则需要采用同样相对于页面计算的框体位置信息 offsetLeft 和 offsetTop
    x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
    y = e.touches[0].pageY - e.touches[0].target.offsetTop;
               
    这样就可以计算出相对位置的信息了:
    // rect = e.target.getBoundingClientRect()
    xOffset = x / rect.width;
    yOffset = y / rect.height;
    
    // xOffset = x / e.touches[0].target.offsetWidth;
    // yOffset = y / e.touches[0].target.offsetHeight;
               

由于在对屏幕进行触摸移动时,默认会拖动页面,为了避免这种情况,需要使用

e.preventDefault()

,另外由于一个触摸点长时间接触屏幕而不移动时,会触发页面菜单,需要通过

contextmenu

事件来禁止长按菜单

放大镜效果放大镜效果
// 禁止长按菜单
document.addEventListener('contextmenu', (e) => {
    e.preventDefault();
})
           
image.addEventListener('touchmove', (e) => {
    // 防止页面被拖动
    e.preventDefault();

    let rect = e.target.getBoundingClientRect();

    // 由于 touch 事件没有 offsetX 和 offsetY 属性,所以需要进行额外的计算操作
    // 可能有多个触摸点,这里只取一个触摸点来计算触摸的位置 e.touches[0]
    // 使用相对于视口计算的触摸点位置 clientX 和 clientY(方法返回的框体位置信息是相对于视口而言的)
    // rect = e.target.getBoundingClientRect()
    let x = e.touches[0].clientX - rect.left;
    let y = e.touches[0].clientY - rect.top;

    // 如果要使用相对于页面计算的触摸点位置 pageX 和 pageY,
    // 则需要采用同样相对于页面计算的框体位置信息 offsetLeft 和 offsetTop
    // let x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
    // let y = e.touches[0].pageY - e.touches[0].target.offsetTop;

    let xOffset = x / rect.width;
    let yOffset = y / rect.height;

    // let xOffset = x / e.touches[0].target.offsetWidth;
    // let yOffset = y / e.touches[0].target.offsetHeight;

    e.target.style.setProperty('--x', xOffset);
    e.target.style.setProperty('--y', yOffset);
});
           

此时有个问题就是当触摸点触摸屏幕但不移动时,图片显示的放大区域可能是不正确的(如下,即使触摸的位置是其他位置,也总是显示图片左上角的那只耳朵)

放大镜效果放大镜效果

这是因为此时触摸点不移动,就不会触发

touchmove

事件,导致无法对图片进行移动,所以这里需要在

touchstart

事件处理函数中添加相关步骤移动图片的步骤

// 这里将触摸移动事件处理函数体抽离为一个独立的函数
image.addEventListener('touchstart', (e) => {
    e.target.setAttribute('zoomed', 1);
    // 避免重新触摸后未移动时图片位置不正确
    moveHandler(e);
});

image.addEventListener('touchmove', moveHandler);

function moveHandler(e) {
    // 防止页面被拖动
    e.preventDefault();

    let rect = e.target.getBoundingClientRect();

    // 由于 touch 事件没有 offsetX 和 offsetY 属性,所以需要进行额外的计算操作
    // 可能有多个触摸点,这里只取一个触摸点来计算触摸的位置 e.touches[0]
    // 使用相对于视口计算的触摸点位置 clientX 和 clientY(方法返回的框体位置信息是相对于视口而言的)
    // rect = e.target.getBoundingClientRect()
    let x = e.touches[0].clientX - rect.left;
    let y = e.touches[0].clientY - rect.top;

    // 如果要使用相对于页面计算的触摸点位置 pageX 和 pageY,则需要采用同样相对于页面计算的框体位置信息 offsetLeft 和 offsetTop
    // let x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
    // let y = e.touches[0].pageY - e.touches[0].target.offsetTop;

    let xOffset = x / rect.width;
    let yOffset = y / rect.height;

    // let xOffset = x / e.touches[0].target.offsetWidth;
    // let yOffset = y / e.touches[0].target.offsetHeight;

    e.target.style.setProperty('--x', xOffset);
    e.target.style.setProperty('--y', yOffset);
}
           

修改后效果如下(现在触摸哪里,放大的位置就是哪里)

放大镜效果放大镜效果

现在还有一个问题就是当触摸点在图片框内移动到框外区域时,

touchmove

事件还是处于被触发的状态,此时触摸点的位置在框外,而对于图片偏移量的计算依然根据触摸点位置计算,那么此时就会导致图片被移动到可见区域外

放大镜效果放大镜效果

为解决这个问题需要限制图片可偏移的范围,只需要做些简单判断即可

function moveHandler(e) {
    // ......
    
    // 使用相对于视口计算的触摸点位置 clientX 和 clientY(方法返回的框体位置信息是相对于视口而言的)
    // rect = e.target.getBoundingClientRect()
    let x = e.touches[0].clientX - rect.left;
    let y = e.touches[0].clientY - rect.top;
    // 限制范围
    x = x < 0 ? 0 : x;
    x = x > rect.width ? rect.width : x;
    y = y < 0 ? 0 : y;
    y = y > rect.height ? rect.height : y;

    // 如果要使用相对于页面计算的触摸点位置 pageX 和 pageY,则需要采用同样相对于页面计算的框体位置信息 offsetLeft 和 offsetTop
    // let x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
    // let y = e.touches[0].pageY - e.touches[0].target.offsetTop;
    // 限制范围
    // x = x < 0 ? 0 : x;
    // x = x > e.touches[0].target.offsetWidth ? e.touches[0].target.offsetWidth : x;
    // y = y < 0 ? 0 : y;
    // y = y > e.touches[0].target.offsetHeight ? e.touches[0].target.offsetHeight : y;

    // ......
}
           

为了让代码看起来NB一点,可以将上述的判断语句合并一下:

function moveHandler(e) {
    // ......
    
    // 限制范围
    x = Math.min(Math.max(0, x), rect.width);
    y = Math.min(Math.max(0, y), rect.height);
    // x = x < 0 ? 0 : x;
    // x = x > rect.width ? rect.width : x;
    // y = y < 0 ? 0 : y;
    // y = y > rect.height ? rect.height : y;

    // ......
    // 限制范围
    // x = Math.min(Math.max(0, x), e.touches[0].target.offsetWidth);
    // y = Math.min(Math.max(0, y), e.touches[0].target.offsetHeight);
    // x = x < 0 ? 0 : x;
    // x = x > e.touches[0].target.offsetWidth ? e.touches[0].target.offsetWidth : x;
    // y = y < 0 ? 0 : y;
    // y = y > e.touches[0].target.offsetHeight ? e.touches[0].target.offsetHeight : y;

    // ......
}
           

至此,触摸点即使移动出了图片框外也可以正确显示放大的图片了

放大镜效果放大镜效果

至此移动端的放大镜效果实现就完成了,现在需要将移动端的相关代码和PC端的相关代码合并达成兼容的目的。为了方便为鼠标事件和触摸事件赋予事件处理函数,同时使代码结构看起来优雅一点,这里我将事件处理函数的代码进行抽离。由于

mouseenter

mouseleave

的事件处理函数分别和

touchstart

touchend

的内容几乎一致,所以这四个事件的处理函数并不需要做太多的差异编码。这里有一个禁止长按菜单的操作(

contextMenu

事件)是只需要在移动端内设置的,所以需要判断此时触发的事件是移动端事件还是PC端的,以此来决定是否要禁止长按菜单

image.addEventListener('mouseenter', enterHandler);
image.addEventListener('mouseleave', leaveHandler);

image.addEventListener('touchstart', enterHandler);
image.addEventListener('touchend', leaveHandler);

// 这里需要特地抽离出一个事件处理函数,因为无法移除一个为匿名函数的监听器
function prevent(e) {
    e.preventDefault();
}

function enterHandler(e) {
    e.target.setAttribute('zoomed', 1);
    // 避免重新触摸后未移动时图片位置不正确
    moveHandler(e);

    if (e.type === 'touchstart') {
        // 禁止长按菜单
        document.addEventListener('contextmenu', prevent)
    } else {
        // 取消禁止长按菜单
        document.removeEventListener('contextmenu', prevent);
    }
}

function leaveHandler(e) {
    e.target.removeAttribute('zoomed');
}
           

mousemove

touchmove

事件的事件处理函数内容差异较大,需要进行的差异编码比较多,其中重要的一个就是对事件类型的判断(详见以下代码)

image.addEventListener('mousemove', moveHandler);
image.addEventListener('touchmove', moveHandler);

function moveHandler(e) {
    let rect = e.target.getBoundingClientRect();

    // 由于 touch 事件没有 offsetX 和 offsetY 属性,所以需要进行额外的计算操作
    let x = 0;
    let y = 0;

    // 对事件类型的判断
    if (['touchstart', 'touchend', 'touchmove'].includes(e.type)) {
        // 防止页面被拖动
    	e.preventDefault();
        
        // 可能有多个触摸点,这里只取一个触摸点来计算触摸的位置 e.touches[0]
        // 使用相对于视口计算的触摸点位置 clientX 和 clientY(方法返回的框体位置信息是相对于视口而言的)
        // rect = e.target.getBoundingClientRect()
        x = e.touches[0].clientX - rect.left;
        y = e.touches[0].clientY - rect.top;
        // 限制范围
        x = Math.min(Math.max(0, x), rect.width);
        y = Math.min(Math.max(0, y), rect.height);
        // x = x < 0 ? 0 : x;
        // x = x > rect.width ? rect.width : x;
        // y = y < 0 ? 0 : y;
        // y = y > rect.height ? rect.height : y;
    } else {
        x = e.offsetX;
        y = e.offsetY;
    }

    let xOffset = x / rect.width;
    let yOffset = y / rect.height;

    e.target.style.setProperty('--x', xOffset);
    e.target.style.setProperty('--y', yOffset);
}
           

至此这个兼容就完成了

精简代码

可以看到,在我尝试使用

getBoundingClientRect()

以及

e.offsetX, e.offsetY

时,兼容PC端和移动端时,代码量有点多,实际上可以改变做法,精简代码

image.addEventListener('mousemove', moveHandler);
image.addEventListener('touchmove', moveHandler);s

function moveHandler(e) {
    let eventObj = null;

    if (['touchstart', 'touchend', 'touchmove'].includes(e.type)) {
        // 防止页面被拖动
        e.preventDefault();

        // 可能有多个触摸点,这里只取一个触摸点来计算触摸的位置 e.touches[0]
        eventObj = e.touches[0];
    } else {
        eventObj = e;
    }

    let x = eventObj.pageX - eventObj.target.offsetLeft;
    let y = eventObj.pageY - eventObj.target.offsetTop;

    // 限制范围
    x = Math.min(Math.max(0, x), eventObj.target.offsetWidth);
    y = Math.min(Math.max(0, y), eventObj.target.offsetHeight);

    let xOffset = x / eventObj.target.offsetWidth;
    let yOffset = y / eventObj.target.offsetHeight;

    e.target.style.setProperty('--x', xOffset);
    e.target.style.setProperty('--y', yOffset);
}
           

总结

放大镜效果涉及到的事件在PC端是

mouseenter

mouseleave

mousemove

,在移动端是

touchstart

touchend

touchmove

。实现的方式有不止一种,但总的来说就三个步骤:进入图片框时放大图片,离开图片框时恢复图片大小并将图片偏移样式清除,在图片框内移动时图片的移动随鼠标或接触点的位置进行变化,保证可视区域当前显示的图片放大位置为 鼠标或接触点在图片框相对位置 和 放大的图片相同相对位置 重叠时的图片部分

参考:

https://www.bilibili.com/video/BV12N411974Q

继续阅读