之前写过一篇可拖动的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. JavaBean知识

    四.JavaBean的概念1.JavaBean一般具有的特点:a.字段都是私有的. private String name;b.提供公共的getter或setter方法(属性).getter或sett ...

  2. [WPF]设置背景色

    程序效果 最终得到程序的运行效果如图.拖动Slider可以使按钮的背景色出现相应变化. 需求分析和架构设计 如果是你,接到了这样的一个程序设计要求,会怎样思考?第一步当然是需求分析啦.这个程序相对简单 ...

  3. [ MySql学习心得 ] --One

    一.安装MySql 1.解压版安装 下载地址: http://dev.mysql.com/downloads/mysql/ 安装及配置教程:http://jingyan.baidu.com/artic ...

  4. TYVJ博弈论

    一些比较水的博弈论...(为什么都没有用到那什么SG呢....) TYVJ 1140  飘飘乎居士拯救MM 题解: 歌德巴赫猜想 #include <cmath> #include < ...

  5. 关于Java深clone 的例子学习

    之前http://www.cnblogs.com/lhppom/p/4857702.html里有提到关于Java的深克隆的学习,深浅区别就是在于仅复制对象引用和复制对象引用所指向的对象,最近在看< ...

  6. Linux 忘记root登录密码解决方法

    很多朋友经常会忘记Linux系统的root密码,linux系统忘记root密码的情况该怎么办呢?重新安装系统吗?当然不用!进入单用户模式更改一下root密码即可. 步骤如下: 重启linux系统 3  ...

  7. JavaScript常用方法100种

    1.输出语句:document.write(""); 2.JS中的注释为// 3.传统的HTML文档顺序是:document->html->(head,body) 4. ...

  8. Lisp 函数

    (quote x) [返回x] >>>>>>>>>>>>>>>>>>>>> ...

  9. RichTextBox着色与着色不闪

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

  10. JAVA/Android Map与String的转换方法

    在Android开发中 Map与String的转换在,在一些需求中经常用到,使用net.sf.json.JSONObject.fromObject可以方便的将string转为Map.但需要导入jar包 ...