前端工程师小A学习JS的旅程
前端工程师小A学习JS的旅程
在网页里,拖拽效果是很常见的形式,实现起来也比较简单,但是这么简单的代码,却能体现出很多前端开发工程湿的JS能力,我们来看看小A工程师的实现路程:
HTML代码:
<!DOCTYPE HTML> <html> <head> <title>拖拽效果</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <style type="text/css"> #drag_box{width: 150px;height: 150px;background-color: #ff0000;position: absolute;margin: 0;top: 80px;left: 0;} #diy,#dix{width: 70px;display: inline-block;height: 30px;} </style> </head> <body> <span id="dix">X:0px</span> <input type="button" value="锁定X轴" id="closeX" data-open="true"> <br/> <span id="diy">Y:80px</span> <input type="button" value="锁定Y轴" id="closeY" data-open="true"> <div id="drag_box"></div> </body> </html>
JS代码:
小A的拖拽JS代码第一版
<script type="text/javascript">
var closeX=document.getElementById("closeX"),closeY=document.getElementById("closeY");
closeX.onclick=function(){
if(this.getAttribute("data-open")=="true"){
this.setAttribute("data-open","false");
this.value="解开X轴";
}else{
this.setAttribute("data-open","true");
this.value="锁定X轴";
}
}
closeY.onclick=function(){
if(this.getAttribute("data-open")=="true"){
this.setAttribute("data-open","false");
this.value="解开Y轴";
}else{
this.setAttribute("data-open","true");
this.value="锁定Y轴";
}
}
var box=document.getElementById('drag_box');
var x=y=0;
var dix=document.getElementById("dix"),diy=document.getElementById("diy");
box.onmousedown=function(event){
var event=event||window.event;
x=event.clientX-this.offsetLeft;
y=event.clientY-this.offsetTop;
this.style.cursor="move";
var that = this;
document.onmousemove=function(event){
var event=event||window.event;
var le=event.clientX-x,to=event.clientY-y;
var maxL = document.documentElement.clientWidth - box.offsetWidth;
var maxT = document.documentElement.clientHeight - box.offsetHeight;
if(le<0){
le=0
}else if(le>maxL){
le=maxL;
}
if(to<80){
to=80
}else if(to>maxT){
to=maxT;
}
if(closeX.getAttribute("data-open")=="true"){
that.style.left=le+"px";
dix.innerHTML="X:"+le+"px";
}
if(closeY.getAttribute("data-open")=="true"){
that.style.top=to+"px";
diy.innerHTML="Y:"+to+"px";
}
if(that.releaseCapture){
that.releaseCapture();
}
return false;
}
this.onmouseup=function(){
document.onmousemove=null;
document.onmouseup = null;
this.style.cursor="default";
if(this.releaseCapture){
this.releaseCapture();
}
return false;
}
if(this.releaseCapture){
this.releaseCapture();
}
return false;
}
</script>
这是小A初学JS一个月写出来的JS代码,完美实现了拖拽的功能,并且也能也能注意在适当的时候阻止事件的默认行为,还能用上if(this.releaseCapture){this.releaseCapture();}这样的语句来防止鼠标离开拖拽BOX。对于小A来说,学习一个月能写出这样的代码来已经实属不易,我们也不得不承认小A是一个学习能力很强的前端工程师。
又学习了一个月小A学到了js的封装,于是重新看了看上面的代码,觉得处理锁定X轴和锁定Y轴的代码有些重复,而且拖拽的对象可能会发生变化,于是小A改造了一下上面的代码,创建了两个方法函数drag和closexy把主体功能封转在两个函数里面:
小A的拖拽JS代码第二版
<script type="text/javascript">
function drag (box) {
var x=y=0;
var dix=document.getElementById("dix"),diy=document.getElementById("diy");
box.onmousedown=function(event){
var event=event||window.event;
x=event.clientX-this.offsetLeft;
y=event.clientY-this.offsetTop;
this.style.cursor="move";
var that = this;
document.onmousemove=function(event){
var event=event||window.event;
var le=event.clientX-x,to=event.clientY-y;
var maxL = document.documentElement.clientWidth - box.offsetWidth;
var maxT = document.documentElement.clientHeight - box.offsetHeight;
if(le<0){
le=0
}else if(le>maxL){
le=maxL;
}
if(to<80){
to=80
}else if(to>maxT){
to=maxT;
}
if(closeX.getAttribute("data-open")=="true"){
that.style.left=le+"px";
dix.innerHTML="X:"+le+"px";
}
if(closeY.getAttribute("data-open")=="true"){
that.style.top=to+"px";
diy.innerHTML="Y:"+to+"px";
}
if(that.releaseCapture){
that.releaseCapture();
}
return false;
}
this.onmouseup=function(){
document.onmousemove=null;
document.onmouseup = null;
this.style.cursor="default";
if(this.releaseCapture){
this.releaseCapture();
}
return false;
}
if(this.releaseCapture){
this.releaseCapture();
}
return false;
}
}
function closexy(xy,obj){
if(obj.getAttribute("data-open")=="true"){
obj.setAttribute("data-open","false");
obj.value="解开"+xy+"轴";
}else{
obj.setAttribute("data-open","true");
obj.value="锁定"+xy+"轴";
}
}
var box=document.getElementById('drag_box');
drag(box);
var closeX=document.getElementById("closeX"),closeY=document.getElementById("closeY");
closeX.onclick=function(){
closexy("X",this);
}
closeY.onclick=function(){
closexy("Y",this);
}
</script>
这样一看,代码量减少了许多,而且显得也比较调理,更重要的是封转后的方法在随意的对象上都可以调用,简单、方便!此时的小A学习js的激情高涨,于是就更加勤奋的学习!
又不知过了多久。小A的js水平有了大幅提高,这个时候小A回头看之前写过的拖拽代码,觉得有很多不妥的地方,比如:没有注意命名空间,没有成模块化、如果拖拽的外围边界不是body了怎么变、如果拖拽的范围变化了呢,拖拽的锁定可不可以做成开放性的呢。基于这些问题,于是小A觉得完全可以把拖拽功能做成一个拖拽库,开放接口,以应付千变万化的拖拽效果和需求,所以小A又写了第三版的拖拽JS代码:
小A的拖拽JS代码第三版
<script type="text/javascript">
/* *
* * dragBox:拖动对象,可以是对象的ID;
* * options:参数;
* * maxContainer:设置拖动外围box,默认为body;
* * minL:离外围边界左边最小距离,默认为0;
* * maxL:离外边界左边最大距离,默认body的宽度-拖动对象宽度;
* * minT:离外围边界上边最小距离,默认为0;
* * maxT:离外围边界最大高度,默认为body高度-拖动对象高度;
* * lockx:是否锁定X轴,默认不锁定;
* * locky:是否锁定Y轴,默认不锁定;
* * onStart:开始拖动回调函数;
* * onMove:拖动过程中回调函数;
* * onStop:拖动结束回调函数;
*/
function Drag(){
this.init.apply(this,arguments);
}
Drag.prototype={
init:function(dragBox,options){
this.dragBox=this.$(dragBox);
this.setOptions(options);
this._moveDrag=this.bind(this,this.moveDrag);
this._stopDrag=this.bind(this,this.stopDrag);
this.maxContainer = this.options.maxContainer||document.documentElement || document.body;
this.minL=this.options.minL||0;
this.maxL=this.options.maxL||Math.max(this.maxContainer.clientWidth,this.maxContainer.scrollWidth)-this.dragBox.offsetWidth;
this.minT=this.options.minT||0;
this.maxT=this.options.maxT||Math.max(this.maxContainer.clientHeight,this.maxContainer.scrollHeight)-this.dragBox.offsetHeight;
this.lockx = this.options.lockx||false;
this.locky = this.options.locky||false;
this.onStart=this.options.onStart||null;
this.onMove=this.options.onMove||null;
this.onStop=this.options.onStop||null;
this.addHandle(this.dragBox, "mousedown", this.bind(this, this.startDrag));
this.haslayout();
},
haslayout:function(){
this.dragBox.style.left=this.minL+"px";
this.dragBox.style.top=this.minT+"px";
},
startDrag:function(event){
var event=event||window.event;
this._x=event.clientX-this.dragBox.offsetLeft;
this._y=event.clientY-this.dragBox.offsetTop;
this.addHandle(document,"mousemove",this._moveDrag);
this.addHandle(document,"mouseup",this._stopDrag);
this.preventDefault(event);
this.dragBox.setCapture && this.dragBox.setCapture();
if(typeof onStart==="function"){
this.onStart();
}
},
moveDrag:function(event){
var event=event||window.event;
this.dragBox.style.cursor = "move";
var le=event.clientX-this._x,to=event.clientY-this._y;
if(le<this.minL){
le=this.minL
}else if(le>this.maxL){
le=this.maxL;
}
if(to<this.minT){
to=this.minT;
}else if(to>this.maxT){
to=this.maxT;
}
if(!this.lockx){
this.dragBox.style.left=le+"px";
}
if(!this.locky){
this.dragBox.style.top=to+"px";
}
this.preventDefault(event);
this.dragBox.setCapture && this.dragBox.setCapture();
if(typeof onMove==="function"){
this.onMove();
}
},
stopDrag:function(){
this.removeHandle(document,"mousemove",this._moveDrag);
this.removeHandle(document,"mouseup",this._stopDrag);
this.dragBox.style.cursor = "default";
this.dragBox.setCapture && this.dragBox.setCapture();
if(typeof onStop==="function"){
this.onStop();
}
},
$:function(id){
return typeof id=="string" ? document.getElementById(id):id;
},
addHandle:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type]=handler;
}
},
removeHandle:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
}else{
element["on"+type]=null;
}
},
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=false;
}
},
setOptions : function(options){
this.options ={};
for (var p in options) this.options[p] = options[p];
},
bind : function (object, fnHandler){
return function (){
return fnHandler.apply(object, arguments)
}
}
};
//应用
var box=document.getElementById("drag_box");
var Mydrag=new Drag(box,{
minT:10,
maxT:100,
lockx:true
});
</script>
这样,一个功能齐全的拖拽库就这样漂亮的诞生了!拖拽库开放接口很齐全,代码页很规范。从此小A就不用害怕任何拖拽功能需求了!
从小A学习js的旅程,我们可以看出,学习JS是一个循序渐进的过程,看似简单的功能,从最开始的实现功能,到不断改进,一直到最后写成一个插件,可以有很多版本,而这些不断改进的过程正是学习JS最好的方法!

浙公网安备 33010602011771号