JavaScript之面向对象案例-放大镜

效果图

在这里插入图片描述

实现原理分析

如图所示

在这里插入图片描述
触发鼠标的移动事件时,根据事件对象的 clientX 和 clientY 属性得到实时的坐标点 x 和 y
值 ,减去 small_box 的 offsetLeft 值cutting_box 的宽度的一半 ,可以得到 cutting_box 的偏移量 left 值,top值同理。当 cutting_box 到达右侧和下侧时,left 和 top 取得最大值。用 实时变化的left和top值 比上 各自的最大值,可得到一个比例,再根据这个比例,算出右侧 big_img 元素的 left 和 top。具体求法是:先求出 big_img 放大后的宽高,由这个宽高求得big_img的 left和top 最大值。在用这个最大值乘以上述的比例值即得到相应的 big_img 的 left 和 top值。
注意点:big_img 放大后的宽高求法
small_box宽高 / cutting_box = big_img宽高 / big_box宽高。(只有big_img宽高未知)

基本页面结构

<div class="small">
	<img src="images/timg.jpg" alt="">
	<span class="grayBox"></span>
</div>
<div class="big">
	<img src="images/timg.jpg" alt="">
</div>

CSS代码

.small {
	width: 400px;
	height: 400px;
	position: relative;
	border:4px solid #ddd;
	box-shadow: 0 0 5px rgba(0,0,0,.5);
}
.small img{
	width: 100%;
	height: 100%;
}
.small .grayBox{
	display: none;
	width: 100px;
	height: 100px;
	box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
	position: absolute;
	left: 0;
	top: 0;
}	
.big{
	width: 400px;
	height: 400px;
	position: absolute;
	left: 700px;
	top: 100px;
	border:1px solid #f10;
	display: none;
	overflow: hidden;
}
.big img{
	position: absolute;
}

面向对象实现

分析(OOA)

  • 元素选择功能
  • 绑定事件驱动
  • 元素的显示与隐藏功能
  • 小图移动,大图的放大跟随移动功能
  • 鼠标滚轮缩放功能

设计(OOD)

  • 构造函数
function Magnifier(){}
  • 初始化各个功能模块
function init(){}
  • 事件绑定功能
function bindEvent(){}
  • 元素的显示与隐藏功能
function eleToggle(){}
  • 小图移动,大图放大跟随功能
function eleMove(){}

编写(OOP)

  • 首先明确应该把所有功能都放到放大镜构造函数的原型上。
  • 其次实例化一个对象时应该传入的是对象类型的参数,如下所示:
new Magnifier({
	small_box : ".small",
	cutting_box : ".grayBox",
	big_box : ".big",
	big_img : ".big img"
});

构造函数此时需要接收实例化时传入的参数:

function Magnifier( options ) {
	// 调用初始化函数,处理接收到的参数对象
	this.init( options );
}

初始化功能完成初始化元素、获取small_box、cutting_box、big_box的offset系列的值:

Magnifier.prototype.init = function( options ){
	// 初始化元素;
	for(var attr in options){
		this[attr+"_ele"] = this.$(options[attr]);
	}
	// 为了节省性能,所以只获取一次offsetLeft;
	this.small_box_offset = {
		left : this.small_box_ele.offsetLeft,
		top  : this.small_box_ele.offsetTop,
		width : parseInt( getComputedStyle(this.small_box_ele).width ),
		height : parseInt( getComputedStyle(this.small_box_ele).width )
	}
	this.cutting_box_offset = {
		width  : parseInt( getComputedStyle(this.cutting_box_ele).width ),
		height : parseInt( getComputedStyle(this.cutting_box_ele).height ),
	}
	this.big_box_offset = {
		width : parseInt( getComputedStyle(this.big_box_ele).width ),
		height : parseInt( getComputedStyle(this.big_box_ele).height ),
	}
	// 标志变量 ,鼠标是否移入放大镜
	this.magnifier_start = false;
	this.bindEvent();
	// 图片缩放功能
	this.scaleBigImg();
}

选择元素功能:

Magnifier.prototype.$ = function(selector){
	return document.querySelector(selector);
}

事件绑定功能:

Magnifier.prototype.bindEvent = function(){
	// 鼠标移入左侧small_box
	this.small_box_ele.addEventListener( "mouseover" , function(){
		// cutting_box big_box元素显示;
		this.eleToggle("show");
		// 修改标志变量为true
		this.magnifier_start = true;
		// 修改事件函数里面的this指向为当前实例对象
	}.bind(this));
	// 鼠标移出左侧small_box
	this.small_box_ele.addEventListener( "mouseout" , function(){
		// cutting_box big_box元素隐藏;
		this.eleToggle("hide");
		this.magnifier_start = false;
	}.bind(this));
	// 鼠标移动,元素运动;
	this.small_box_ele.addEventListener("mousemove" , function( evt ){
		var e = evt || event;
		// 获取鼠标点距离浏览器可视区的 x y 值
		var x = e.clientX ;
		var y = e.clientY ;
		// 调用factoryPosition处理得到的坐标值
		this.res = this.factoryPosition( x , y );
		// 把处理好后的坐标值传入eleMove方法,改变相应的left、top值
		this.eleMove( this.res );
	}.bind(this)); 
	// 滚轮事件;
	document.addEventListener("mousewheel" , function( evt ){
		// 如果鼠标未移入放大镜,则不执行滚轮事件函数
		if(!this.magnifier_start){ return false }
		var e = evt || event;
		// 判定滚轮向上(缩小)还是向下(放大);
		this.changeCutBoxScale( e.wheelDelta > 0 ? "narrow" : "large" );
	}.bind(this));
}	

元素显示隐藏功能:

Magnifier.prototype.eleToggle = function( type ){
	// 根据type类型,判定元素的display的属性值 block | none
	this.cutting_box_ele.style.display = type === "show" ? "block" : "none";
	this.big_box_ele.style.display = type === "show" ? "block" : "none";
}

处理鼠标移动时得到的坐标点 x 和 y 值:

Magnifier.prototype.factoryPosition = function( x , y ){
	// 根据接收到的 x 和 y 计算得到 cutting_box 的 left 和 top 偏移量
	var _left =  x - this.small_box_offset.left - this.cutting_box_offset.width / 2;
	var _top  = y - this.small_box_offset.top - this.cutting_box_offset.height / 2
	// cutting_box 的 left 和 top 的最大值
	var _left_max = this.small_box_offset.width - this.cutting_box_offset.width;
	var _top_max = this.small_box_offset.height - this.cutting_box_offset.height;
	// 最小值边界监测;
	_left = _left <= 0 ? 0  : _left;
	_top  = _top  <= 0 ? 0  : _top
	// 最大值检测
	_left = _left >= _left_max ? _left_max : _left;
	_top = _top >= _top_max ? _top_max : _top;
	// 返回处理好的坐标点值 以及 移动的距离与最大值的比例系数
	return {
		x : _left,
		y : _top,
		xp: _left / _left_max,
		yp:_top / _top_max
	}
}

小图移动,大图放大跟随功能:

Magnifier.prototype.eleMove =  function( position_obj ){
	// 左侧cutting_box移动范围
	this.cutting_box_ele.style.left = position_obj.x + "px";
	this.cutting_box_ele.style.top  = position_obj.y + "px";
	// 大图big_img的移动范围。cutting_box和big_img的移动方向时相反的
	this.big_img_ele.style.left = -position_obj.xp * this.big_img_boundary.left_max + "px";
	this.big_img_ele.style.top  = -position_obj.yp * this.big_img_boundary.top_max + "px";
}

放大图片功能:

Magnifier.prototype.scaleBigImg = function(){
	// 放大的比例 ;
	var width_p  = this.big_box_offset.width / this.cutting_box_offset.width;
	var height_p = this.big_box_offset.height / this.cutting_box_offset.height;
	// 获得了big_img放大之后的宽高;
	this.big_img_offset = {
		width  : width_p * this.small_box_offset.width,
		height : height_p * this.small_box_offset.height,
	}
	// 计算出big_img运动的边界;
	this.big_img_boundary = {
		left_max : this.big_img_offset.width  - this.big_box_offset.width,
		top_max  : this.big_img_offset.height - this.big_box_offset.height
	}
	// 给图片设置等比例宽高;
	this.big_img_ele.style.width  = this.big_img_offset.width + "px";
	this.big_img_ele.style.height = this.big_img_offset.height + "px";
}

鼠标滚轮滚动时同时需要改变左侧 cutting_box 的大小:

Magnifier.prototype.changeCutBoxScale = function( type ){
	switch ( type ) {
		// 放大
		case "large":
			this.cutting_box_offset.width += 2;
			this.cutting_box_offset.height += 2;
			// 让cutting_box 向左 向上移动 让鼠标始终保持在中心位置	
			this.res.x --;
			this.res.y --;	
			break;
		// 缩小
		case "narrow":
			this.cutting_box_offset.width  -= 2;
			this.cutting_box_offset.height -= 2;
			this.res.x ++;
			this.res.y ++;
			break;
		default:
			break;
	}
	this.cutting_box_ele.style.width = this.cutting_box_offset.width + "px";
	this.cutting_box_ele.style.height = this.cutting_box_offset.height + "px";
	// 位置改变之后,调用相应的比例计算工具;
	this.scaleBigImg();
	// 重新进行大图运动的计算;
	this.eleMove(this.res);
}

功能补充:多图片切换,可以放大相应的图片。
添加标签:data-src自定义属性存放不同的图片路径

<button class="btn" data-src=""><img src="" alt=""></button>
<button class="btn" data-src=""><img src="" alt=""></button>

最后只需在实例化放大镜对象后,分别给每个按钮绑定点击或者移入事件,再替换 small 和 big 容器中的 img 的 src 的属性值为相应的 data-src 的属性值即可,如下所示:

// 选中所有代表不同图片的button按钮
var btns = document.querySelectorAll(".btn");
// 选中small 和 big 容器中的 img 标签
var imgs = document.querySelectorAll(".big img,.small img");
for(var i = 0 ; i < btns.length ; i ++){
	btns[i].onclick = function(){
		// 获取每个按钮上的不同的 data-src 属性
		var src = this.getAttribute("data-src");
		for(var k = 0 ; k < imgs.length ; k ++){
			// 替换相应的 src 属性的属性值
			imgs[k].src = src;
		}
	}
}
发布了3 篇原创文章 · 获赞 0 · 访问量 39

猜你喜欢

转载自blog.csdn.net/zpy16104/article/details/105009562