最近一直在看javascript的书籍,有些东西在书上看着貌似理解了,但是在真正动手实践时,其实有些细节你根本不了解。所以看起来就算是一个简单的效果,写起来也未必简单,就算写起来简单,写的代码也未必规范、可维护性等等。无奈,一直学习编程以来都是眼高手低,导致什么都写不出来。在自己没有足够的功底写出好的代码出来,学习大牛的代码也是一直高效的方式。以下是一个拖放的效果,参考的代码,重构以下,加以理解学习。

首先来看效果:

拖动div

拖放状态:未开始

【程序说明】

拖动原理:其实就是在拖动块上监听mousedown事件,鼠标点击时,通过事件对象获取对应的坐标参数。然后鼠标移动时再监听document上的mousemove事件,获取鼠标的clientX 和clientY坐标然后设置拖动块的left 和 top。

首先是监听mousedown事件

EventUtil.addEventHandler(this.Drag, "mousedown", BindAsEventListener(this, this.Start)); 

然后在Start上添加mousemove 和 mouseup 事件

//监听mousemove 和 mouseup事件
EventUtil.addEventHandler(document, "mousemove", this._fM);
EventUtil.addEventHandler(document, "mouseup", this._fS);

鼠标移动时,设置拖动块的left 和 top 属性 :

 if(!this.LockX)this.Drag.style.left = iLeft + "px";
if(!this.LockY)this.Drag.style.top = iTop + "px"; 

水平和垂直锁定:通过判断LockX 和lockY属性来限制对于的top 和 left 属性即可。

范围限制锁定:通过计算容器的宽高和拖动块的宽高差值来设定最大left值和top值,来限制拖动块的left值和top值会在一定的范围里。

完整DEMO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript拖放效果</title>
    <style type="text/css">
     
    </style>
</head>
<body>
    <div id="drag-wrap" style="height: 300px;margin:10px;border:5px solid #FF8000;background:#8080C0;position: relative;">
         <div class="draggable" id="drag" style="width:100px;height: 100px;position: absolute;top: 100px;left:100px;background:#eee;border:1px solid #aceaac;cursor: move;">拖动div</div>
    </div>
    <input id="idReset" type="button" value="复位" />
    <input id="idLock" type="button" value="锁定全部" />
    <input id="idLockX" type="button" value="锁定水平" />
    <input id="idLockY" type="button" value="锁定垂直" />
    <input id="idLimit" type="button" value="范围锁定" />
    <input id="idLimitOff" type="button" value="取消范围锁定" />
    <br />拖放状态:<span id="idShow">未开始</span>
    <script type="text/javascript">
        /**
          *工具函数
          */
         var isIE = (document.all) ? true : false ;
 
         var $$ = function(id){
             return "string" == typeof id ? document.getElementById(id) : id;
         };
 
         var Class = {
            create: function() {
                return function() { this.initialize.apply(this, arguments); }
            }
        };
 
        var Extend = function(destination,source){
            for(var property in source){
                destination[property] = source[property];
            }
        };
 
        var BindAsEventListener = function(object,func){
            return function(event){
                return func.call(object,event || window.event);
            }
        };
 
        var Bind = function(object,func){
            return function(){
                return func.apply(object,arguments);
            }
        };
 
         /**
          *跨浏览器事件对象
          */
        var EventUtil = {
            //事件注册处理程序
            addEventHandler:function(oTarget,sEventType,fnHandler){
                 if(oTarget.addEventListener){
                     oTarget.addEventListener(sEventType,fnHandler,false);
                 }else if(oTarget.attachEvent){
                     oTarget.attachEvent("on"+sEventType,fnHandler);
                 }else{
                     oTarget["on"+sEventType] = fnHandler;
                 }
             },
             //事件移除处理程序
             removeEventHandler:function(oTarget,sEventType,fnHandler){
                 if(oTarget.removeEventListener){
                     oTarget.removeEventListener(sEventType,fnHandler,false);
                 }else if(oTarget.detachEvent){
                     oTarget.detachEvent("on"+sEventType,fnHandler);
                 }else{
                     oTarget["on"+sEventType] = null;
                 }
             },
             getEvent:function(event){
                 return event ? event : window.event;
             },
             getTarget:function(event){
                 return event.target || event.srcElement;
             }
        };   
 
        /**
          *拖放程序
         */
         var Drag= Class.create();
 
         Drag.prototype = {
             //初始化对象
             initialize:function(drag,options){
                 this.Drag = $$(drag);//拖放对象
                 this._x = this._y = 0;//记录鼠标相对于拖放对象的位置
                 //事件对象(用于绑定移除事件)
                 this._fM = BindAsEventListener(this, this.Move);
                this._fS = Bind(this, this.Stop);
                this.Drag.style.position = "absolute";
                this.marginLeft = this.marginTop = 0;//记录margin
                //设置参数
                this.setOptions(options);
                //获取相关参数及类型转换
                this.Limit = !!this.options.Limit;//转换为布尔型
                this.mxLeft = parseInt(this.options.mxLeft);
                this.mxRight = parseInt(this.options.mxRight);
                this.mxTop = parseInt(this.options.mxTop);
                this.mxBottom = parseInt(this.options.mxBottom);
 
                this.Lock = !!this.options.Lock;
                this.LockX = !!this.options.LockX;
                this.LockY = !!this.options.LockY;
 
                this.onStart = this.options.onStart;
                this.onMove = this.options.onMove;
                this.onStop = this.options.onStop;
 
                this._Handle = $$(this.options.Handle) || this.Drag;
                this._mxContainer = $$(this.options.mxContainer) || null;
                //监听拖动对象mousedown事件
                EventUtil.addEventHandler(this.Drag, "mousedown", BindAsEventListener(this, this.Start));
 
             },
             //准备拖动   
             Start:function(oEvent){
                 if(this.Lock){return;}//如果锁定则不执行
                 //记录mousedown触发时鼠标相对于拖放对象的位置
                 this._x = oEvent.clientX - this.Drag.offsetLeft;
                this._y = oEvent.clientY - this.Drag.offsetTop;
                //监听mousemove 和 mouseup事件
                EventUtil.addEventHandler(document, "mousemove", this._fM);
                EventUtil.addEventHandler(document, "mouseup", this._fS);
             },   
             //拖动
             Move:function(oEvent){
                 //设置移动参数
                 var iLeft = oEvent.clientX - this._x , iTop = oEvent.clientY - this._y;
                 //设置范围限制
                 if(this.Limit){
                     //设置范围参数
                    var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom;
                    //如果设置了容器,再修正范围参数
                    if(!!this._mxContainer){
                        mxLeft = Math.max(mxLeft, 0);
                        mxTop = Math.max(mxTop, 0);
                        mxRight = Math.min(mxRight, this._mxContainer.clientWidth);
                        mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);
                    };
                    //修正移动参数
                    iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
                    iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);
                 }
                 //XY锁定
                 if(!this.LockX)this.Drag.style.left = iLeft + "px";
                if(!this.LockY)this.Drag.style.top = iTop + "px";
                //执行附加程序
                this.onMove();
             },
             //停止拖动
             Stop:function(){
                EventUtil.removeEventHandler(document, "mousemove", this._fM);
                EventUtil.removeEventHandler(document, "mouseup", this._fS);
                //执行附加程序
                this.onStop();
             },
             //设置默认参数
             setOptions:function(options){
                 this.options = {//默认值
                    Handle:            "",//设置触发对象(不设置则使用拖放对象)
                    Limit:            false,//是否设置范围限制(为true时下面参数有用,可以是负数)
                    mxLeft:            0,//左边限制
                    mxRight:        9999,//右边限制
                    mxTop:            0,//上边限制
                    mxBottom:        9999,//下边限制
                    mxContainer:    "",//指定限制在容器内
                    LockX:            false,//是否锁定水平方向拖放
                    LockY:            false,//是否锁定垂直方向拖放
                    Lock:            false,//是否锁定
                    Transparent:    false,//是否透明
                    onStart:        function(){},//开始移动时执行
                    onMove:            function(){},//移动时执行
                    onStop:            function(){}//结束移动时执行
                };
                Extend(this.options, options || {});
             }
         };
 
        //初始化拖动对象
        var drag = new Drag('drag',{mxContainer:'drag-wrap',Limit:true,
                onStart: function(){ $$("idShow").innerHTML = "开始拖放"; },
                onMove: function(){ $$("idShow").innerHTML = "left:"+this.Drag.offsetLeft+";top:"+this.Drag.offsetTop; },
                onStop: function(){ $$("idShow").innerHTML = "结束拖放"; }
                });
        $$("idReset").onclick = function(){
            drag.Limit = true;
            drag.mxLeft = drag.mxTop = 0;
            drag.mxRight = drag.mxBottom = 9999;
            drag.LockX = drag.LockY = drag.Lock = false;
            $$("idShow").innerHTML = "复位";
        }
        $$("idLock").onclick = function(){ drag.Lock = true;$$("idShow").innerHTML = "锁定全部";}
        $$("idLockX").onclick = function(){ drag.LockX = true; $$("idShow").innerHTML = "锁定水平";}
        $$("idLockY").onclick = function(){ drag.LockY = true; $$("idShow").innerHTML = "锁定垂直";}
        $$("idLimit").onclick = function(){     drag.mxRight = drag.mxBottom = 200;drag.Limit = true;$$("idShow").innerHTML = "范围锁定"; }
        $$("idLimitOff").onclick = function(){ drag.Limit = false; $$("idShow").innerHTML = "取消范围锁定";}
    </script>
</body>
</html>

javascript 拖放效果的更多相关文章

  1. JavaScript实现拖放效果

    JavaScript实现拖放效果 笔者实现该效果也是套用别人的轮子的.传送门 然后厚颜无耻的贴别人的readme~,笔者为了方便查阅就直接贴了,有不想移步的可以看这篇.不过还是最好请到原作者的GitH ...

  2. Sortable – 简单灵活的 JavaScript 拖放排序插件

    当需要在网站中添加拖放排序功能的时候,jQuery UI 的排序组件可能是最流行的解决方案.今天给大家介绍另一款简单灵活的 JavaScript 拖放排序插件——Sortable,它使用 HTML5 ...

  3. 自学HTML5第三节(拖放效果)

    今天来看看网页上的拖放效果,首先来看看什么是拖放———— 拖放 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. 浏览器支持 Inte ...

  4. Javascript动画效果(三)

    Javascript动画效果(三) 前面我们已经介绍了速度动画.透明度动画.多物体运动和任意值变化,并且我们在Javascript动画效果(二)中介绍到我们封装了一个简单的插件雏形,接下来我们对前面的 ...

  5. Javascript动画效果(一)

    Javascript动画效果(一) 前面我们介绍了Javascript的回到顶部效果,今天呢,我们对Javascript动画做进一步的研究.在这篇博文中我们只介绍简单的匀速运动.简单的缓冲运动和简单的 ...

  6. Javascript动画效果(二)

    Javascript动画效果(二) 在前面的博客中讲了简单的Javascript动画效果,这篇文章主要介绍我在改变之前代码时发现的一些问题及解决方法. 在前面的多物体宽度变化的例子中,我们给其增加代码 ...

  7. Javascript动画效果(四)

    Javascript动画效果(四) 前面我们自己写了一个小小的关于js动画的插件,下面我们来使用之前的框架来完成我们想要的动画效果.我们经常在淘宝网中看到,鼠标经过某一图片时,该图片有从上滚出而又从下 ...

  8. javascript动画效果之缓冲动画(修改版)

    在编写多块同时触发运动的时候,发现一个BUG, timer = setInterval(show, 30);本来show是一个自定义函数,当设为timer = setInterval(show(one ...

  9. javascript动画效果之透明度(修改版)

    在编写多块同时触发运动的时候,发现一个BUG, timer = setInterval(show, 30);本来show是一个自定义函数,当设为timer = setInterval(show(one ...

随机推荐

  1. Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if expl

    检查你的用户名和密码是否正确 ,以及位置是否正确:

  2. 不要错过 DevOps 之父出席的2017 DevOpsDays 北京站!

    通过 DevOpsDays 活动,Patrick 将 DevOps 这项伟大的运动带到了地球的东方,带到了北京.同时,他将亲自参加2017年3月18日的 DevOpsDays 北京站,并作精彩演讲. ...

  3. Javaweb开发中URL路径的使用

    看到博客园孤傲苍狼的web系列文章中有关于URL路径的使用文章后,感觉自己对URL的使用清楚了很多,自己再对着动手写一遍以加深记忆. JavaWeb开发中常看到URL以"/"开头, ...

  4. windows server 2008系统VPN服务配置

    转自:http://www.softxp.net/article/win2008-vpn/,,仅作自己的笔记用 Windows sever 2008 R2的NPS(network policy ser ...

  5. vue+webpack构建项目

    概述 -- 项目中会用到的插件 vue-router vue-resource 打包工具 webpack 依赖环境 node.js start 安装vue开发的模板 # 全局安装 vue-cli $ ...

  6. iOS NSNotificationCenter 移除通知带来的crash

    Where to remove observer for NSNotification? 在dealloc方法中移除通知观察者带来crash NSNotificationCenter中的通知消息已经发 ...

  7. ACM第五次积分赛

    做出三道题,第二名,总积分上升到第八名,继续加油! SAU-ACM总比赛成绩 姓名     账号  上学期成绩 第一次成绩 第二次成绩 第三次成绩 第四次成绩 第五次成绩 总成绩 张国庆 143401 ...

  8. ngDialog 设置其宽度大小

    [ngdialog弹窗大小设置(angularjs)] 方法一:添加css样式属性 css: .ngdialog.ngdialog-theme-plain.custom-width-70 .ngdia ...

  9. 拿来之笔 希望铭记 笔记 出处 http://www.jianshu.com/p/acb8885283dc

    最近有机会对不同岗位的应聘者进行面试,其中有架构师.技术经理.开发岗位.谈谈几个印象深刻的. 面试者一,女性.重点大学硕士,从事软件技术工作十四年,应聘架构师岗位.按照套路问了下对于软件架构的认识和理 ...

  10. jmeter命令行运行-分布式测试

    上一篇文章我们说到了jmeter命令行运行但是是单节点下的, jmeter底层用java开发,耗内存.cpu,如果项目要求大并发去压测服务端的话,jmeter单节点难以完成大并发的请求,这时就需要对j ...