JavaScript面向对象编程实例——放大镜效果

今天,我们要实现一个放大镜效果,具体效果如下:
效果图
首先,先写结构。
我们需要两个div,分别存放放大前和放大后的图片。
其次就是需要一个可以随着鼠标移动的盒子,表示放大的区域。
为了方便叙述,所以我把存放放大前图片的盒子成为小盒子,存放放大后图片的盒子成为大盒子,随鼠标移动的盒子成为鼠标盒子

	/*存放放大前图片的盒子*/
	<div class="small">
		<img src="./img/1.jpg" alt="">
		/*放大区域*/
    	<span class="grayBox"></span>
    </div>
    /*存放当大后图片的盒子*/
	<div class="big">
    	<img src="./img/1.jpg" alt="">
	</div>

然后,我们写一些CSS样式美化一下界面。

/*我这里是为了偷懒,如果这样写会浪费一些性能*/
*{
	margin: 0;
	padding: 0;
}
.small {
	width: 400px;
	height: 400px;
	position: relative;
	margin-left: 200px;
	margin-top: 100px;
	border:4px solid #ddd;
	box-shadow: 0 0 5px rgba(0,0,0,.5);
}
.small img{
	width: 100%;
	height: 100%;
}
.small .grayBox{
	width: 200px;
	height: 200px;
	background-image: url(../img/1.jpg);
	background-size:400px 400px;
	background-position: 0 0;
	box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
	position: absolute;
	left: 0;
	top: 0;
	display : none;
}	
.big{
	width: 400px;
	height: 400px;
	position: absolute;
	left: 700px;
	top: 100px;
	border:4px solid #f10;
	overflow: hidden;
	display : none;
}
.big img{
	position: absolute;
}

效果如下:
css
结构和样式写完了,我们要开始实现功能了。
我认为的面向对象的编程方式应该有有三个阶段,分别是OOA(面对对象分析)、OOD(面对对象设计)和OOP(面对对象编程)。
首先就是OOA阶段,找出自己想要的功能

//OOA
//初始化
//元素选择器
//事件绑定器
//显示隐藏器
//位置加工器
//跟随移动器
//比例获取器

大致就这多,数量也不一定准确,可以后期再进行添加补充。
其次是OOD阶段对于OOA阶段功能的设计。

//OOD
function Magnifier(){}
Magnifier.prototype = {
//更改指向方向
constructor : Magnifier,
//初始化
init : function(){},
//元素选择器
$ : function(){},
//事件绑定器
bindEvent : function(){},
//显示隐藏器
eleToggle : function(){},
//位置加工器
factoryPosition : function(){},
//跟随移动器
eleMove : function(){},
//比例获取器
getPercentage : function(){}
}

最后是OOPOOD设计的完善与实现。

//OOP
function Magnifier(options){
	//从实例对象里传入options,里面存储着
	this.init(options);
}
Magnifier.prototype = {
//更改指向方向
constructor : Magnifier
}
  • 初始化
//初始化
init : function(options){
	for(var attr in options){
		//使用for...in遍历对象,获取DOM
		this[attr+"_ele"] = this.$(options[attr]);
	}
	//获取小盒子的属性,方便运算时使用,因为offset比较消耗性能,所以尽量在全局获取
	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).height)
	}
	//小盒子在使用offset获取其宽高会获取到边框,使宽高数据不精确
	//鼠标盒子在鼠标未移入的时候是隐藏的,使用offset不能获取正确的数据
	//所以使用getComputedStyle代替,直接获取元素的非行内样式的数据
	//因为非行内样式宽高一般带着单位,需要使用parseInt去掉单位
	this.cutting_box_offset = {
		width : parseInt( getComputedStyle(this.cutting_box_ele).width ),
		height : parseInt( getComputedStyle(this.cutting_box_ele).height ),
	}
	//让事件绑定器生效
	this.bindEvent();
}
  • 元素选择器
//元素选择器
$ : function(selector){
//元素选择器的作用返回是获取相对应属性的DOM
	return docement.querySelector(selector);
}
  • 事件绑定器
//事件绑定器
bindEvent : function(){
	this.small_box_ele.addEventListener( "mouseover" , function(){
		// 鼠标移入元素显示;
		this.eleToggle("show");
	}.bind(this));
	this.small_box_ele.addEventListener( "mouseout" , function(){
		// 鼠标移出元素隐藏;
		this.eleToggle("hide");
	}.bind(this));
		// 元素运动;
	this.small_box_ele.addEventListener("mousemove" , function( ev ){
		var e = ev || event;
		//获取鼠标距离屏幕的距离
		var x = e.clientX ;
		var y = e.clientY ;
		//然后使用位置加工器加工位置
		this.res = this.factoryPosition( x , y )
		this.eleMove( this.res.x , this.res.y );
		//改变大盒子图片的位置和宽高
		this.getPercentage();
		//让鼠标盒子的背景图片随着鼠标反向移动,实现鼠标盒子和小盒子背景的一致
		this.cutting_box_ele.style.backgroundPosition =(-this.res.x)+"px "+(-this.res.y)+"px";
	}.bind(this));
}
  • 跟随移动器
//跟随移动器
eleMove : function(x,y){
	//鼠标盒子随着传入的参数x和y进行移动
	this.cutting_box_ele.style.left = x + "px";
	this.cutting_box_ele.style.top  = y + "px";
}
  • 显示隐藏器
//显示隐藏器
eleToggle : function(type){
	//判断鼠标盒子和大盒子在type是show的时候显示,在type为hide的时候隐藏
	this.cutting_box_ele.style.display = type === "show" ? "block" : "none";
	this.big_box_ele.style.display = type === "show" ? "block" : "none";
}
  • 位置加工器
//位置加工器
factoryPosition : function(x,y){
	//为了让光标永远在鼠标盒子的中心
	//x是鼠标在屏幕的位置,减去小盒子到屏幕左侧的距离,剩下的是鼠标位置距离小盒子边框的距离
	//在减去鼠标盒子宽高的一半,让鼠标盒子向左移动,让鼠标在水平方位上在鼠标盒子中间
	//y也是如此,让鼠标在垂直方向上在鼠标盒子中间
	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
	// 边界监测,防止鼠标盒子跟随鼠标移出小盒子
	//小盒子的宽高减去鼠标盒子的宽高是鼠标盒子位置坐标的最大值
	//大于最大值让其坐标等于最大值,以免鼠标盒子越界
	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
	}
}
  • 比例获取器
//比例获取器
getPercentage : function(){
	//获得大盒子的宽高
	this.big_box_wh ={
		width : parseInt(getComputedStyle(this.big_box_ele).width),
		height : parseInt(getComputedStyle(this.big_box_ele).height),
	}
	//获取小盒子和鼠标盒子的比例
	var width_per =  this.small_box_offset.width / this.cutting_box_offset.width ;
	var height_per = this.small_box_offset.height / this.cutting_box_offset.height;
	//按照相同的比例设置大框图片的宽高
	this.big_img_ele.style.width = this.big_box_wh.width * width_per +"px";
	this.big_img_ele.style.height = this.big_box_wh.height * height_per +"px";
	//让大盒子的图片按照比例反方向移动
	this.big_img_ele.style.left = -(this.res.x * width_per) +"px";
	this.big_img_ele.style.top = -(this.res.y * height_per) +"px";
}
//创建实例对象
new Magnifier({
 	small_box : ".small",
    cutting_box : ".grayBox",
    big_box : ".big",
    big_img : ".big img"
});

这样下来,简单的放大镜效果就做好了。
嗯?有小伙伴问我为什么和效果图不一样?
好吧,完善一下,最终代码如下
结构:

<div class="small_bg">
    <div class="small">
        <img src="./img/1.jpg" alt="" class="active">
         <span class="grayBox"></span>
         
    </div>
    <div class="list">
        <img src="./img/1.jpg" alt="">
        <img src="./img/2.jpg" alt="">
        <img src="./img/3.jpg" alt="">
        <img src="./img/4.jpg" alt="">
    </div>
</div>   
<div class="big">
    <img src="./img/1.jpg" alt="">
</div>

样式:

*{
	margin: 0;
	padding: 0;
}
.small {
	width: 400px;
	height: 400px;
	position: relative;	
}
.small_bg{
	width: 400px;
	height: 500px;
	margin-left: 200px;
	margin-top: 100px;
	border:4px solid #ddd;
	box-shadow: 0 0 5px rgba(0,0,0,.5);
}
.list{
	height: 80px;
	border-top: 4px #ddd solid;
}
.list img{
	float: left;
	width: 100px;
	height: 100px;
}
.small img{
	width: 100%;
	height: 100%;
	display: none;
}
.small img.active{
	display: block;
}
.small .wrap{
	width: 100%;
	height: 100%;
	position: absolute;
	z-index: 999;
}
.small .grayBox{
	display: none;
	width: 200px;
	height: 200px;
	background-image: url(../img/1.jpg);
	background-size:400px 400px;
	background-position: 0 0;
	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:4px solid #f10;
	display: none;
	overflow: hidden;
}
.big img{
	position: absolute;
}

行为:

unction Magnifier( options ) {
		this.init( options );
	}
	Magnifier.prototype = {
	constructor : Magnifier , 
	init : function( options ){
	for(var attr in options){
		this[attr+"_ele"] = this.$(options[attr]);
	}
	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).height)
	}
	this.cutting_box_offset = {
		width  : parseInt( getComputedStyle(this.cutting_box_ele).width ),
		height : parseInt( getComputedStyle(this.cutting_box_ele).height ),
	}
	this.bindEvent();
	},
	$ : function(selector){
			return document.querySelector(selector);
		},
	bindEvent : function(){
		this.small_box_ele.addEventListener( "mouseover" , function(){
			this.eleToggle("show");
		}.bind(this));
		this.small_box_ele.addEventListener( "mouseout" , function(){
			this.eleToggle("hide");
		}.bind(this));
		this.small_box_ele.addEventListener("mousemove" , function( ev ){
			var e = ev || event;
			var x = e.clientX ;
			var y = e.clientY ;
			this.res = this.factoryPosition( x , y )
			this.eleMove( this.res.x , this.res.y );
			this.getPercentage();
			this.cutting_box_ele.style.backgroundPosition =(-this.res.x)+"px "+(-this.res.y)+"px";
		}.bind(this));
		this.small_box_ele.addEventListener("mousewheel",function( ev){
			var e = ev||event;
			this.cuttingChange(e.wheelDelta > 0 ? "narrow" : "enlarge");
		}.bind(this));
		},
	eleToggle : function( type ){
		this.cutting_box_ele.style.display = type === "show" ? "block" : "none";
		this.big_box_ele.style.display = type === "show" ? "block" : "none";
	},
	eleMove : function( x , y ){
		this.cutting_box_ele.style.left = x + "px";
		this.cutting_box_ele.style.top  = y + "px";
	},
	getPercentage : function(){
		this.big_box_wh ={
			width : parseInt(getComputedStyle(this.big_box_ele).width),
			height : parseInt(getComputedStyle(this.big_box_ele).height),
		}
		var width_per =  this.small_box_offset.width / this.cutting_box_offset.width ;
		var height_per = this.small_box_offset.height / this.cutting_box_offset.height;
		this.big_img_ele.style.width = this.big_box_wh.width * width_per +"px";
		this.big_img_ele.style.height = this.big_box_wh.height * height_per +"px";
			this.big_img_ele.style.left = -(this.res.x * width_per) +"px";
			this.big_img_ele.style.top = -(this.res.y * height_per) +"px";
		},
		factoryPosition : function( x , y ){
			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
			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
			}
		}
	}
new Magnifier({
    small_box : ".small",
    cutting_box : ".grayBox",
    big_box : ".big",
    big_img : ".big img"
});
    var btns = document.querySelectorAll(".list img");
    var imgs = document.querySelectorAll(".big img,.small img");
    var small = document.querySelector(".grayBox");

	for( var i= 0 ; i < btns.length ; i++){
		btns[i].addEventListener( "click" , function(){
			var src = this.getAttribute("src");
			for(var k = 0 ; k < imgs.length ; k ++){
                imgs[k].src = src;
                small.style.backgroundImage = "url(../img/"+ i +".jpg)";   
			}
		})
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值