原生JS实现电商平台图片放大(放大镜功能)

先看看某宝的效果

好多美女。。。我们是来干正事的,如图当我们移动蓝色框,右边随着移动
原生JS实现电商平台图片放大(放大镜功能)_第1张图片
我们可以利用值准备一张图片,使用transform:scale(*)来实现放大缩小;也可以准备两张图片,一张大一张小的来实现,这里我准备了两张(400400,800800)

结构

small为400的图片,big为800的图片

	<div class="box">
		
		<div class="small_cont">
			<img src="images/small.jpg" alt="" class="small_img">
			<div class="mark">div>
			
			<div class="big">
				<img src="images/big.jpg" alt="" class="big_img">
				
			div>
		div>
	div>

标记块/小盒子 = 大盒子/图片
可以在JS进行控制,也可以在css控制,为了方便在css控制
样式我们需要根据具体情况具体分析

	

一些API的介绍

offset家族(以下解释不同,但类似的可以结合一起看,如width和height)

1.offsetHeight:元素的offsetHeight是一种元素CSS高度的衡量标准,包括元素的边框、内边距和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度。检测盒子的高度,包括padding和border;不包括margin
2. offsetWidth:是一个只读属性,返回一个元素的布局宽度。一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(border)、水平线上的内边距(padding)、竖直方向滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)的值。检测盒子的宽度,包括padding和border;不包括margin
3. offsetParent:是一个只读属性,返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素。如果没有定位的元素,则 offsetParent 为最近的 table, table cell 或根元素.
4. offsetLeft:是一个只读属性,返回当前元素左上角相对于 HTMLElement.offsetParent 节点的左边界偏移的像素值。返回距离定位盒子左侧的边界,没有定位父系盒子没有则返回,距离左侧(body)的位置
5. offsetTop:为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部的距离。

client家族(以下解释不同,但类似的可以结合一起看,如left和top)
  1. clientX:MouseEvent.clientX 是只读属性, 它提供事件发生时的应用客户端区域的水平坐标 (与页面坐标不同)。例如,不论页面是否有水平滚动,当你点击客户端区域的左上角时,鼠标事件的 clientX 值都将为 0
  2. clientY:跟上面换汤不换药;e.clienY通常是鼠标距离我们浏览器最上面的距离(不是页面)
  3. clientWidth:Element.clientWidth 属性表示元素的内部宽度,以像素计。该属性包括内边距,但不包括垂直滚动条(如果有)、边框和外边距。(element.getBoundingClientRect()是有小数值的)
  4. clientHeight 可以通过 CSS height + CSS padding - 水平滚动条高度 (如果存在)来计算.
  5. clientTop:一个元素顶部边框的宽度(以像素表示)。不包括顶部外边距或内边距。clientTop 是只读的。
  6. clientLeft:表示一个元素的左边框的宽度,以像素表示。如果元素的文本方向是从右向左(RTL, right-to-left),并且由于内容溢出导致左边出现了一个垂直滚动条,则该属性包括滚动条的宽度。clientLeft 不包括左外边距和左内边距。clientLeft 是只读的。
pageX

pageX 是一个由MouseEvent接口返回的相对于整个文档的x(水平)坐标以像素为单位的只读属性。

这个属性将基于文档的边缘,考虑任何页面的水平方向上的滚动。举个例子,如果页面向右滚动 200px 并出现了滚动条,这部分在窗口之外,然后鼠标点击距离窗口左边 100px 的位置,pageX 所返回的值将是 300。

var pageX = event.pageX;

首先看看步骤(整体代码在最后)

  1. 获取:我们需要的元素,获取一些能获取到的宽高,其余初始化
// 1. 获取
let box = document.querySelector('.box') //获取最外层盒子 
let mark = document.querySelector('.mark') //获取需要移动的标记块
let smallBox = document.querySelector('.small_cont') //小盒子
let bigBox = document.querySelector('.big') //大盒子
let bigImg = document.querySelector('.big>img') //大盒子

let markWidth = 0 //初始化mark的宽度
let markHeight = 0 //初始化mark的高度
let smallBoxWidth = smallBox.offsetWidth
let smallBoxHeight = smallBox.offsetHeight
let bigBoxWidth = 0//初始化大盒子的宽度
let bigImgWidth = 0//初始化图片的宽度
let maxX //通过最大移动距离求出比例
  1. 鼠标进入时显示大盒子和标记块
smallBox.onmouseenter = function(){ //防止冒泡(不使用onmouseover)
	mark.style.display = 'block'
// 2.1显示后获取mark的宽高
    markWidth = mark.offsetWidth
// 2.2显示大盒子
    bigBox.style.display = 'block'
}
  1. 离开时隐藏
smallBox.onmouseleave = function(){ //防止冒泡(不使用onmouseover)
	mark.style.display = 'none'
	bigBox.style.display = 'none'
}
  1. 获取鼠标在小盒子移动时的位置
let distanceY = 0 //鼠标的移动
let distanceX = 0 
smallBox.onmousemove = function(e){
	e = window.event || e //兼容写法
	e.stopPropagation() //阻止冒泡
	distanceX = e.pageX - this.offsetLeft
	distanceY = e.pageY - this.offsetTop
}
  1. 使得mark跟着鼠标移动,保持鼠标在mark的中间
    markWidth = mark.offsetWidth
    markHeight = mark.offsetHeight
	mark.style.left = distanceX - markWidth/2 + 'px'
	mark.style.top =  distanceY - markHeight/2 + 'px'
  1. 我们限制mark的活动范围在小盒子内,超出则置于顶点,即不能超出
if(distanceX<=markWidth/2){
		distanceX = markWidth/2
	}else if(distanceX>=smallBoxWidth - markWidth/2){
		distanceX = smallBoxWidth - markWidth/2
	}
	if(distanceY<=markHeight/2){
		distanceY = markHeight/2
	}else if(distanceY>=smallBoxHeight - markHeight/2){
		distanceY = smallBoxHeight - markHeight/2
	}
  1. 当mark移动时,那么大盒子的图片也按照一定的比例移动(即mark相对定位移动多少。大盒子的图片也移动多少),通过已知条件来求该比例
  2. 这个比例: 图片的最大移动距离/mark的最大移动距离
    bigBoxWidth = bigBox.clientWidth
    bigImgWidth = bigImg.offsetWidth
    maxX = (bigImgWidth - bigBoxWidth)/(smallBoxWidth - markWidth)
  1. 移动大盒子的图片,我们需要根据distance来移动,因为我们是mark来移动的,所以要根据mark来定位实现移动大盒子的图片,他们的关系为
    distance(X、Y)+ -markWidth/2 = mark的定位(Left、Right)
  2. 根据比例来移动
	bigImg.style.left = -(maxX * (distanceX-markWidth/2)) + 'px'
	bigImg.style.top = -(maxX * (distanceY-markWidth/2)) + 'px'
  1. 代码融合成一起实现放大镜
window.onload = function(){
let box = document.querySelector('.box') //获取最外层盒子 
let mark = document.querySelector('.mark') //获取需要移动的标记块
let smallBox = document.querySelector('.small_cont') //小盒子
let smallImg = document.querySelector('.small_cont>img')
let bigBox = document.querySelector('.big') //大盒子
let bigImg = document.querySelector('.big>img') //大盒子

let markWidth = 0 //初始化mark的宽度
let markHeight = 0 //初始化mark的高度
let smallBoxWidth = smallBox.offsetWidth
let smallBoxHeight = smallBox.offsetHeight
let bigBoxWidth = 0//初始化大盒子的宽度
let bigImgWidth = 0//初始化图片的宽度
let maxX //通过最大移动距离求出比例
smallBox.onmouseenter = function(){ //防止冒泡(不使用onmouseover)
	mark.style.display = 'block'
    markWidth = mark.offsetWidth
    markHeight = mark.offsetHeight
    bigBox.style.display = 'block'
    bigBoxWidth = bigBox.clientWidth
    bigImgWidth = bigImg.offsetWidth
    maxX = (bigImgWidth - bigBoxWidth)/(smallBoxWidth - markWidth)
}
smallBox.onmouseleave = function(){ //防止冒泡(不使用onmouseover)
	mark.style.display = 'none'
	bigBox.style.display = 'none'
}
let distanceY = 0 //鼠标的移动
let distanceX = 0 
smallBox.onmousemove = function(e){
	e = window.event || e //兼容写法
	e.stopPropagation() //阻止冒泡
	distanceX = e.pageX - this.offsetLeft
	if(distanceX<=markWidth/2){
		distanceX = markWidth/2
	}else if(distanceX>=smallBoxWidth - markWidth/2){
		distanceX = smallBoxWidth - markWidth/2
	}
	distanceY = e.pageY - this.offsetTop
	if(distanceY<=markHeight/2){
		distanceY = markHeight/2
	}else if(distanceY>=smallBoxHeight - markHeight/2){
		distanceY = smallBoxHeight - markHeight/2
	}
	mark.style.left = distanceX - markWidth/2 + 'px'
	mark.style.top =  distanceY - markHeight/2 + 'px'

	bigImg.style.left = -(maxX * (distanceX-markWidth/2)) + 'px'
	bigImg.style.top = -(maxX * (distanceY-markWidth/2)) + 'px'

}
}

你可能感兴趣的:(js)