之前写过一篇可拖动的DIV讲如何实现可拖动的元素,最后提出了几点不足,这篇文章主要就是回答着三个问题

1. 浏览器兼容性

2. 边界检查

3. 拖动卡顿、失灵

先附上上次代码

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css" >
html,body
{
height:100%;
width:100%;
padding:0;
margin:0;
} .dialog
{
width:250px;
height:250px;
position:absolute;
background-color:#ccc;
-webkit-box-shadow:1px 1px 3px #292929;
-moz-box-shadow:1px 1px 3px #292929;
box-shadow:1px 1px 3px #292929;
margin:10px;
} .dialog-title
{
color:#fff;
background-color:#404040;
font-size:12pt;
font-weight:bold;
padding:4px 6px;
cursor:move;
} .dialog-content
{
padding:4px;
}
</style>
</head>
<body>
<div id="dlgTest" class="dialog">
<div class="dialog-title">Dialog</div>
<div class="dialog-content">
This is a draggable test.
</div>
</div>
<script type="text/javascript">
var Dragging=function(validateHandler){ //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
var draggingObj=null; //dragging Dialog
var diffX=0;
var diffY=0; function mouseHandler(e){
switch(e.type){
case 'mousedown':
draggingObj=validateHandler(e);//验证是否为可点击移动区域
if(draggingObj!=null){
diffX=e.clientX-draggingObj.offsetLeft;
diffY=e.clientY-draggingObj.offsetTop;
}
break; case 'mousemove':
if(draggingObj){
draggingObj.style.left=(e.clientX-diffX)+'px';
draggingObj.style.top=(e.clientY-diffY)+'px';
}
break; case 'mouseup':
draggingObj =null;
diffX=0;
diffY=0;
break;
}
}; return {
enable:function(){
document.addEventListener('mousedown',mouseHandler);
document.addEventListener('mousemove',mouseHandler);
document.addEventListener('mouseup',mouseHandler);
},
disable:function(){
document.removeEventListener('mousedown',mouseHandler);
document.removeEventListener('mousemove',mouseHandler);
document.removeEventListener('mouseup',mouseHandler);
}
}
} function getDraggingDialog(e){
var target=e.target;
while(target && target.className.indexOf('dialog-title')==-1){
target=target.offsetParent;
}
if(target!=null){
return target.offsetParent;
}else{
return null;
}
} Dragging(getDraggingDialog).enable();
</script>
</body>
</html>

浏览器兼容性

这个是最好解决的问题了,看看上面代码涉及到浏览器兼容性的地方无非就是event获取及事件源获取、事件绑定,为此特意写两个函数来做此事。

  function addEvent(element, type, key, handler) {//绑定事件处理程序
if (element[type + key])
return false;
if (typeof element.addEventListener != "undefined") {
element[type + key] = handler;
element.addEventListener(type, handler, false);
}
else {
element['e' + type + key] = handler;
element[type + key] = function () {
element['e' + type + key](window.event); //解决IE浏览器event及this问题
};
element.attachEvent('on' + type, element[type + key]);
}
return true;
} function removeEvent(element, type, key) {//移除事件
if (!element[type + key])
return false; if (typeof element.removeEventListener != "undefined") {
element.removeEventListener(type, element[type + key], false);
}
else {
element.detachEvent("on" + type, element[type + key]);
element['e' + type + key] = null;
} element[type + key] = null;
return true;
}

使用这两个函数用于添加和移除事件,就可以解决浏览器兼容性问题,有兴趣的同学可以研究一下,这是根据jQuery作者John Resig写法的改版,参数key是绑定函数的自定义唯一标识,用于removeEvent时取消绑定,改版后代码是这样

   var Dragging = function (validateHandler) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
var draggingObj = null; //dragging Dialog
var diffX = 0;
var diffY = 0; function mouseHandler(e) {
switch (e.type) {
case 'mousedown':
draggingObj = validateHandler(e);//验证是否为可点击移动区域
if (draggingObj != null) {
diffX = e.clientX - draggingObj.offsetLeft;
diffY = e.clientY - draggingObj.offsetTop;
}
break; case 'mousemove':
if (draggingObj) {
draggingObj.style.left = (e.clientX - diffX) + 'px';
draggingObj.style.top = (e.clientY - diffY) + 'px';
}
break; case 'mouseup':
draggingObj = null;
diffX = 0;
diffY = 0;
break;
}
}; return {
enable: function () {
addEvent(document, 'mousedown', 'drag-down', mouseHandler);
addEvent(document, 'mousemove', 'drag-move', mouseHandler);
addEvent(document, 'mouseup', 'drag-up', mouseHandler);
},
disable: function () {
removeEvent(document, 'mousedown', 'drag-down');
removeEvent(document, 'mousemove', 'drag-move');
removeEvent(document, 'mouseup', 'drag-up');
}
}
} function getDraggingDialog(e) {
var target = e && e.target ? e.target : window.event.srcElement;
while (target && target.className.indexOf('dialog-title') == -1) {
target = target.offsetParent;
}
if (target != null) {
return target.offsetParent;
} else {
return null;
}
} Dragging(getDraggingDialog).enable();

边界处理

这个问题说起来也简单,可以在函数调用的时候传入边界值,每次移动的时候判断是否出了边界,这样改动一下

         var Dragging = function (conf) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
var draggingObj = null; //dragging Dialog
var diffX = 0, diffY = 0; var minX = conf.left != undefined ? conf.left : Number.NEGATIVE_INFINITY;
var maxX = conf.right != undefined ? conf.right : Number.POSITIVE_INFINITY;
var minY = conf.top != undefined ? conf.top : Number.NEGATIVE_INFINITY;
var maxY = conf.bottom != undefined ? conf.bottom : Number.POSITIVE_INFINITY; var draggingObjWidth = 0,
draggingObjHeight = 0; function mouseHandler(e) {
switch (e.type) {
case 'mousedown':
draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
if (draggingObj != null) {
diffX = e.clientX - draggingObj.offsetLeft;
diffY = e.clientY - draggingObj.offsetTop;
var size = draggingObj.getBoundingClientRect();
draggingObjWidth = size.right - size.left;
draggingObjHeight = size.bottom - size.top;
}
break; case 'mousemove':
if (draggingObj) {
var x = e.clientX - diffX;
var y = e.clientY - diffY;
if (x > minX && x < maxX - draggingObjWidth) {
draggingObj.style.left = x + 'px';
}
if (y > minY && y < maxY - draggingObjHeight) {
draggingObj.style.top = y + 'px';
}
}
break; case 'mouseup':
draggingObj = null;
diffX = 0;
diffY = 0;
break;
}
}; return {
enable: function () {
addEvent(document, 'mousedown', 'drag-down', mouseHandler);
addEvent(document, 'mousemove', 'drag-move', mouseHandler);
addEvent(document, 'mouseup', 'drag-up', mouseHandler);
},
disable: function () {
removeEvent(document, 'mousedown', 'drag-down');
removeEvent(document, 'mousemove', 'drag-move');
removeEvent(document, 'mouseup', 'drag-up');
}
}
} function getDraggingDialog(e) {
var target = e && e.target ? e.target : window.event.srcElement;
while (target && target.className.indexOf('dialog-title') == -1) {
target = target.offsetParent;
}
if (target != null) {
return target.offsetParent;
} else {
return null;
}
} var config = {
validateHandler: getDraggingDialog,
top: document.documentElement.clientTop,
right: document.documentElement.clientWidth,
bottom: document.documentElement.clientHeight,
left: document.documentElement.clientLeft
} Dragging(config).enable();

如果希望Dialog只能在可视窗口拖动,就可以像上面那样对config参数自定义四个边界值,如果仍然希望没有边界的拖动,则可以四个边界问题不处理,但是validateHandler属性是必须的。

拖动卡顿、失效

关于拖动卡顿在复杂的页面有位明显,一个重要原因就是拖动的时候计算太多导致,不要以为在若动的时候页面就仅仅处理拖动部分的代码,没拖动细微的一下页面都要进行reflow,计算布局所有页面元素的位置,所以复杂的页面自然会卡顿,我们能够处理的只能是是代码的计算尽量简单,为了防止误导读者,我在上面的版本中其实已经做了此项工作,把能够提前计算的的变量值尽量都在函数初始化、mousedown的时候做,再就是尽量使用值变量,避免JavaScript[频繁层层搜索变量引用,看一下低效版的拖动(可不要学会)

    function mouseHandler(e) {
switch (e.type) {
case 'mousedown':
draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
break; case 'mousemove':
if (draggingObj) {
diffX = e.clientX - draggingObj.offsetLeft; //如果这两句也不定义变量,每次使用都要取event的属性值和draggingObj的属性值
diffY = e.clientY - draggingObj.offsetTop;
var size = draggingObj.getBoundingClientRect(); //每移动一下都要算一下大小,实际没必要,拖动不不会改变元素大小 if ((e.clientX - diffX) > minX && (e.clientX - diffX) < maxX - (size.right - size.left)) {//每次都要再算两遍e.clientX - diffX
draggingObj.style.left = x + 'px';
}
if ((e.clientY - diffY) > minY && (e.clientY - diffY) < maxY - (size.bottom - size.top)) {//每次都要再算两遍e.clientY - diffY
draggingObj.style.top = y + 'px';
}
}
break; case 'mouseup':
draggingObj = null;
diffX = 0;
diffY = 0;
minX = 0;
break;
}
};

有同学会说了你都处理了为什么每次还是会拖着拖着就鼠标就出去了,然后就失效了呢?仔细看看每次失效的时候页面上中会伴随着文字被选中,而且仔细观察这个真的会影响拖动,处理一下,拖动的时候不允许选中文字

.disable-select *
{
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
 function mouseHandler(e) {
switch (e.type) {
case 'mousedown':
draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
if (draggingObj != null) {
diffX = e.clientX - draggingObj.offsetLeft;
diffY = e.clientY - draggingObj.offsetTop; var size = draggingObj.getBoundingClientRect();
draggingObjWidth = size.right - size.left;
draggingObjHeight = size.bottom - size.top;
document.body.className += ' disable-select'; //禁止选中
document.body.onselectstart = function () { return false; };
}
break; case 'mousemove':
if (draggingObj) {
var x = e.clientX - diffX;
var y = e.clientY - diffY;
if (x > minX && x < maxX - draggingObjWidth) {
draggingObj.style.left = x + 'px';
}
if (y > minY && y < maxY - draggingObjHeight) {
draggingObj.style.top = y + 'px';
}
}
break; case 'mouseup':
draggingObj = null;
diffX = 0;
diffY = 0;
document.body.className = document.body.className.replace(' disable-select', '');
document.body.onselectstart = null;
break;
}
};

最后

最后的源码就是这样的

 <!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css">
html, body
{
height: %;
width: %;
padding: ;
margin: ;
} .dialog
{
width: 250px;
height: 250px;
position: absolute;
background-color: #ccc;
-webkit-box-shadow: 1px 1px 3px #;
-moz-box-shadow: 1px 1px 3px #;
box-shadow: 1px 1px 3px #;
} .dialog-title
{
color: #fff;
background-color: #;
font-size: 12pt;
font-weight: bold;
padding: 4px 6px;
cursor: move;
} .dialog-content
{
padding: 4px;
} .disable-select *
{
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
</style>
</head>
<body>
<div id="dlgTest" class="dialog">
<div class="dialog-title">Dialog</div>
<div class="dialog-content">
This is a draggable test.
</div>
</div> <script type="text/javascript">
function addEvent(element, type, key, handler) {//绑定事件处理程序
if (element[type + key])
return false;
if (typeof element.addEventListener != "undefined") {
element[type + key] = handler;
element.addEventListener(type, handler, false);
}
else {
element['e' + type + key] = handler;
element[type + key] = function () {
element['e' + type + key](window.event); //解决IE浏览器event及this问题
};
element.attachEvent('on' + type, element[type + key]);
}
return true;
} function removeEvent(element, type, key) {//移除事件
if (!element[type + key])
return false; if (typeof element.removeEventListener != "undefined") {
element.removeEventListener(type, element[type + key], false);
}
else {
element.detachEvent("on" + type, element[type + key]);
element['e' + type + key] = null;
} element[type + key] = null;
return true;
}
</script> <script type="text/javascript">
var Dragging = function (conf) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
var draggingObj = null; //dragging Dialog
var diffX = , diffY = ; var minX = conf.left != undefined ? conf.left : Number.NEGATIVE_INFINITY;
var maxX = conf.right != undefined ? conf.right : Number.POSITIVE_INFINITY;
var minY = conf.top != undefined ? conf.top : Number.NEGATIVE_INFINITY;
var maxY = conf.bottom != undefined ? conf.bottom : Number.POSITIVE_INFINITY; var draggingObjWidth = ,
draggingObjHeight = ; function mouseHandler(e) {
switch (e.type) {
case 'mousedown':
draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
if (draggingObj != null) {
diffX = e.clientX - draggingObj.offsetLeft;
diffY = e.clientY - draggingObj.offsetTop; var size = draggingObj.getBoundingClientRect();
draggingObjWidth = size.right - size.left;
draggingObjHeight = size.bottom - size.top;
document.body.className += ' disable-select'; //禁止选中
document.body.onselectstart = function () { return false; };
}
break; case 'mousemove':
if (draggingObj) {
var x = e.clientX - diffX;
var y = e.clientY - diffY;
if (x > minX && x < maxX - draggingObjWidth) {
draggingObj.style.left = x + 'px';
}
if (y > minY && y < maxY - draggingObjHeight) {
draggingObj.style.top = y + 'px';
}
}
break; case 'mouseup':
draggingObj = null;
diffX = ;
diffY = ;
document.body.className = document.body.className.replace(' disable-select','');
document.body.onselectstart = null;
break;
}
}; return {
enable: function () {
addEvent(document, 'mousedown', 'drag-down', mouseHandler);
addEvent(document, 'mousemove', 'drag-move', mouseHandler);
addEvent(document, 'mouseup', 'drag-up', mouseHandler);
},
disable: function () {
removeEvent(document, 'mousedown', 'drag-down');
removeEvent(document, 'mousemove', 'drag-move');
removeEvent(document, 'mouseup', 'drag-up');
}
}
} function getDraggingDialog(e) {
var target = e && e.target ? e.target : window.event.srcElement;
while (target && target.className.indexOf('dialog-title') == -) {
target = target.offsetParent;
}
if (target != null) {
return target.offsetParent;
} else {
return null;
}
} var config = {
validateHandler: getDraggingDialog,
top: document.documentElement.clientTop,
right: document.documentElement.clientWidth,
bottom: document.documentElement.clientHeight,
left: document.documentElement.clientLeft
}; Dragging(config).enable();
</script>
</body>
</html>

试试真的好了很多,然而鼠标要是移动的快还是会拖离,以为就是这样了呢,但试了试jQuery的Dialog控件,拖动基本流畅,这让人情何以堪,今天天气好,出去找妹子了,改天研究研究jQuery是怎么写的吧

可拖动的DIV续的更多相关文章

  1. jQuery实现鼠标拖动改变Div高度

    最近项目中需要在DashBoard页面做一个事件通知栏,该通知栏固定位于页面底部,鼠标拖动该DIV实现自动改变高度扩展内容显示区域. 以下是一个设计原型,基于jQuery实现,只实现了拖动效果,没有做 ...

  2. 鼠标拖动改变DIV等网页元素的大小的最佳实践

    1.初次实现 1.1 html代码 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" la ...

  3. jquery 拖动改变div大小

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 可拖动的div——demo

    可拖动的div——demo 我们经常会遇到这样的注册界面 我们以前经常可以遇到这种需要注册的网站,如上图: 上图有一个特点,即是上述注册框其实是一个div,同时可以拖动,以下做一个简单的实例,就可以实 ...

  5. 可拖动的DIV

    在做WEB UI设计的时候,拖动某个HTML元素已经成为一种不能忽视的用户界面模式,比较典型的应用例子就是Dialog,一个元素是怎么实现拖动的呢?其实原理非常简单,要想实现首先得了解几个基本知识. ...

  6. 【转】弹出可拖动的DIV层提示窗口

    来源:www.divcss5.com <html> <head> <meta http-equiv="Content-Type" content=&q ...

  7. 创建一个可拖动的DIV

    var drag = function(){ var obj = document.getElementById("id"); var s = obj.style; var b = ...

  8. [置顶] 原创鼠标拖动实现DIV排序

    先上效果图: 对比传统的排序,这是一个很不错的尝试,希望对大家有启发. 大家可以参考我的上一篇博文:http://blog.csdn.net/littlebo01/article/details/12 ...

  9. 如何用JavaScript做一个可拖动的div层

    可拖动的层在Web设计中用处很多,比如在某些需要自定义风格布局的应用中,控件就需要拖动操作,下面介绍一个,希望可以满足你的需求,顺便学习一下可拖动的层是如何实现的. 下面是效果演示: 这个DIV可以移 ...

随机推荐

  1. python 跨模块实现按照文件大小,日期实现日志分割,反转

    笔者的一个自动化测试平台项目,采用了python作为后端服务器语言.项目基于快速成型目的,写了一个极其简陋的日志记录功能,支持日志记录到文件和支持根据日志级别在终端打印不同颜色的log.但随着测试平台 ...

  2. IP地址框

    //IP地址框 // 此段代码:独立的获取本机IP地址和计算机名 WORD wVersionRequested; WSADATA wsaData; char name[255]; CString ip ...

  3. LInux javac时, 提示command not found

    这个是我之前看了很多的论坛发现的问题,我想了很久也没有发现问题,明明路径都是对的,配置文件也没有错误,为什么最后却只有执行java好使,但是执行javac不好使 因为java分两个版本一个是jre,一 ...

  4. css3 风车旋转

    <style> .box{width:400px;height:400px;margin:100px auto;transition:1s;} .box div{width:180px;h ...

  5. android 的数学公式图片转换

    在应用中的数学公式是不能直接以文本显示和输入的,包括在一些学习类网站上看到的公式,他们都是以gif图片的形式展示出来的.而怎么样生成各种各样的gif图片形式的数学公式呢,此处未作深入研究,我所知道的是 ...

  6. 使用Notepad++作为IDE代替Source Insight

    视图-->Folder as Workspace 视图-->函数列表 设置-->语言格式设置-->选择主题 插件-->Plugin Manager-->装上NppG ...

  7. RichTextBox着色与着色不闪

    近来写的一个数据查询分析器意外的快捷,不到两晚工夫就搞定了.完成度相当的高.当然少不了关键字着色,不过着色的代码来自的网上,看了一下感觉过多的循环 //文本框改变事件 int index = this ...

  8. Inno setup定制安装界面

    Innosetup功能很强大,可以通过它提供的Wizard接口来定制界面,但我对PASCAL语言不熟悉,也不清楚通过那种接口可改动的范围有多大,最后做出来的效果是否好,所以选择了通过一个DLL来实现我 ...

  9. hdu acm 1028 数字拆分Ignatius and the Princess III

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  10. javascript练习-私有状态

    在经典的面向对象编程中,经常需要将对象的某个状态封装或隐藏在对象内,只有通过对象的方法才能访问这些状态,对外只暴露一些重要的状态可以直接编写.这是就需要私有状态. function Range(fro ...