本文代码地址(第一节):https://github.com/dirstart/js-exam/blob/master/拖拽div1.html

第二节:https://github.com/dirstart/js-exam/blob/master/拖拽div2.html

第三节:https://github.com/dirstart/js-exam/blob/master/拖拽div3.html

本来只是想要实现鼠标放置并且一个悬浮窗的功能,结果慢慢回顾基础突然想起以前看到过的拖拽,就都需要定位来说,悬浮窗和拖拽有相似的地方。

那么,怎么实现拖拽呢,我们需要什么呢?

  • 首先我们看功能,拖拽就是 鼠标按住 => 鼠标移动 => 鼠标松开
  • 接着我们需要什么? 最后的结果是拖住的块要动,而且是跟着鼠标移动 = > 改变块的 style.top ,要注意, offsetHeight是只读的,style.top是可写的,这个是我以前踩过的坑,不过已经忘了是在哪里踩的了。因为要改变,所以我们首先要获取,因此 => 获取style的函数

http://www.cnblogs.com/jshen/archive/2012/11/29/2794292.html (关于style.top和offsetTop)

  • 最后我们所记录下的数据: 1.物块的起始位置 2.鼠标移动的位置 3.物块最后的位置

    我们能够想到的过程: a.鼠标按下,物块不动(但是告诉浏览器我们准备好了,我点着的是box) b.鼠标移动,物块动,用数组保存鼠标移动的位置 c.鼠标放下,物块不动,一波操作结束

    实际上块的移动距离是鼠标mousedown点到mousemove的变动距离

大致就先这样,现在开始我们的表演。


First Blood : 获取css属性

首先证明一下,为什么不直接用DOM的参数来直接获取属性?

css部分

		*{margin: 0;padding: 0;}
#box{
margin-top: 240px;
margin-left: 500px;
width: 100px;
height: 100px;
background: #bfbfbf;
cursor: move;
}

body部分

	<div id="box"></div>

js部分

	let box=document.getElementById("box");
// box.style.marginTop=600+"px";
box.onmouseover=function(event){
console.log(parseInt(box.style.marginTop));
}

如上,最后显示的是NaN,可是我们明明在CSS中写了margin-top呀,于是我们将注释去掉,发现去掉之后显示的是600.

=> 原因在于,style.marginTop获取不了外部的样式。

链接如下 : http://www.cnblogs.com/cythia/p/6721145.html

所以引出能够获取外部样式的 方法 currentStyle和getComputedStyle.之后,因为IE支持前者,FF和Chrome支持后者。

let oStyle=this.currentStyle?this.currentStyle:window.getComputedStyle(this,null);

	box.onmouseover=function(event){
let oStyle=this.currentStyle?this.currentStyle:window.getComputedStyle(this,null);
console.log(parseInt(box.style.marginTop)); // NaN
console.log(oStyle.height); // 100px
}

发现可用,之后进入我们的第二步。


Second , 获取鼠标的动态并根据此改变我们的块已达到拖拽的目的

let event=event||window.event; 通过此句获得当前鼠标的地址,这样的赋值依旧是为了处理兼容性问题。

!!!!!!!!!!!!很幸运,我们见到了一个新坑,这里报错了

报错信息:Uncaught SyntaxError: Identifier 'event' has already been declared

这个错误应该是跟let有关,在这里用以前的var就不会出错。

在这里我先扔出大概的原理链接,因为我也不是很懂==,let x=x这样是会报错的:

https://www.zhihu.com/question/62966713/answer/204279809

那么我们先用回 var event=event||window.event,继续我们的旅程。

	let box=document.getElementById("box");
let disX=disY=0;
let startX=startY=0;
let flag=false;
box.onmousedown=function(event){
var event=event||window.event;
// 阻止事件冒泡
if(event && event.stopPropagation){
event.stopPropagation();
}else{
window.event.cancelBubble=true;
}
// 记录下mousedown点的距离
flag=true;
startX=event.clientX;
startY=event.clientY;
console.log("down");
}
box.onmousemove=function(event){
if(flag===false) return ;
let oStyle=this.currentStyle?this.currentStyle:window.getComputedStyle(this,null);
disX=event.clientX-startX;
disY=event.clientY-startY;
box.style.marginLeft=parseInt(oStyle.marginLeft)+disX+"px";
box.style.marginTop=parseInt(oStyle.marginTop)+disY+"px";
}
document.onmouseup=function(){
flag=false;
}

我们发现能够移动,但是非常卡顿,很不平滑,完全不像每次计算 鼠标变动距离的样子。

问题已发现:少了一句话。 我们需要在 onmousemove 再加一句话,因为我们的startX始终没有改变,而实际上每一次的移动都应该改变我们上一次的起始点。

	box.onmousemove=function(event){
............................................
startX=event.clientX;
startY=event.clientY;
}

加上我们的基本功能就算完成了。

但是还有个问题,当我们的鼠标移出了box的范围后,因为我们使用的是 box.onmousemove ,我们鼠标到了document就不行了。

这又是我们的思维漏洞,不过改倒是非常容易

box.onmousemove改成'document.onmousemove,将里面的三个 this改成box` 即可。

第一版代码地址:https://github.com/dirstart/js-exam/blob/master/拖拽div1.html

那么这样我们的第二阶段就OK了,我们先看看网上其他的例子。


现在能想到的优化:1.样式可以更好看 2.可以给提示和信息 3.不让div移出浏览器框外。


看完fgm.cc里面的拖拽之后的

首先记录下过程中可能要看的知识点:http://blog.csdn.net/u012309349/article/details/50663841

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{margin: 0;padding: 0;}
ul,li{
list-style: none;
}
#box{
cursor: move;
position: absolute;
top: 50%;
left : 50%;
width: 300px;
height: 150px;
margin: -75px 0 0 -150px;
background: #C0E4DF;
border: 1px solid #3E2D2D;
}
html{
font-size: 12px;
background: #F0ADAD;
}
.header{
border-bottom: 1px solid #3E2D2D;
height: 40px;
line-height: 40px;
font-size: 16px;
text-align: center;
color: #8C1F1F;
}
</style>
</head>
<body>
<div id="box">
<p class="header">我是被拖拽的小窗口</p>
<p>拖拽是否开启</p><span></span>
<ul>
<li>位置X : <span id="displayX"></span></li>
<li>位置Y : <span id="displayY"></span></li>
</ul>
</div>
</body>
<script type="text/javascript">
let oBox=document.getElementById("box"),
oX=document.getElementById('displayX'),
oY=document.getElementById('displayY'),
isDrag=false,
temX=0,
temY=0,
disX=0,
disY=0;
oBox.onmousedown=(event)=>{
var event=event||window.event;
isDrag=true;
temX=event.clientX;
temY=event.clientY;
disX=temX-oBox.offsetLeft;
disY=temY-oBox.offsetTop; this.setCapture && this.setCapture(); return false;
}
document.onmousemove=(event)=>{
if(!isDrag) return ;
var event=event||window.event;
temX=event.clientX-disX;
temY=event.clientY-disY;
oBox.style.left=temX+"px";
oBox.style.top=temY+"px";
// oBox.style.marginTop = oBox.style.marginLeft = 0; }
document.onmouseup=(event)=>{
isDrag=false;
}
</script>
</html>

这是根据fgm.cc网站修改的部分,我们重点关注一下注释中的// oBox.style.marginTop = oBox.style.marginLeft = 0;,这里有个问题,如果不加这句话的话鼠标不会保持在我们第一次放下的oBox内的位置。

其实原因是这个样子的,因为我们初始的时候为了让元素居中,所以我们用了 top:50%;left:50%; margin-left: #(负一半的元素宽度) ; margin-top: #(负一半的元素高度)

上面的目的是为了居中,而此后,因为我们直接通过 offsetLeft和offsetTop来设定了位置,这个时候的margin-left和margin-top如果不清楚,就会造成 ---- box盒子往 左上偏 。

可以这样理解 。我们这个时候已经不用 top 和 left 的绝对定位了, 而我们 派出去生物天敌 margin却还在起着它的作用 ,这就像当年的罗斯福与破坏生物的故事了。

So,我们得加上那句注释掉的话。

接下来的任务是怎么让盒子不移出我们的视线之外。

其实照网上的这种写法,要直接限定盒子简直是太容易了,不得不承认别人的逻辑比我的好上太多了。代码如下:

	document.onmousemove=(event)=>{
if(!isDrag) return ;
var event=event||window.event;
temX=event.clientX-disX;
temY=event.clientY-disY;
oBox.style.marginTop = oBox.style.marginLeft = 0; console.log(temX);
// 做判断
temX=temX<0?0:temX;
temX=temX>maxX?maxX:temX;
temY=temY<0?0:temY;
temY=temY>maxY?maxY:temY; oBox.style.left=temX+"px";
oBox.style.top=temY+"px";
oBox.style.marginTop = oBox.style.marginLeft = 0; }

至于如何来美化它,这里就不再阐述了,不过之后再来介绍一种用其他思路来实现的代码。


Third 第三种方法的实现


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{margin: 0;padding: 0;}
body{
background: #6A3545;
}
#box{
position: absolute;
left: 500px;
top: 300px;
width: 100px;
height: 100px;
border: 1px solid #fde331;
background: #1A5F5C;
cursor: move;
}
#temp{
position: absolute;
width: 100px;
height: 100px;
background: #bfb171;
opacity: 0.6;
}
</style>
</head>
<body>
<div id="box">
</div>
</body>
<script type="text/javascript">
var zIndex=1;
var oBox=document.getElementById('box');
function getStyle(ele,attr){
return ele.currentStyle?ele.currentStyle[attr]:getComputedStyle(ele,null)[attr];
}
oBox.onmousedown=function(event){
var event=event||window.event;
var disX=event.clientX-oBox.offsetLeft;
var disY=event.clientY-oBox.offsetTop;
var maxLeft=document.documentElement.clientWidth - oBox.offsetWidth;
var maxTop=document.documentElement.clientHeight - oBox.offsetHeight;
var oTemp=document.createElement("div");
oTemp["id"]="temp";
oTemp.style.left=getStyle(oBox,"left");
oTemp.style.top=getStyle(oBox,"top");
oTemp.style.zIndex=zIndex++;
document.body.appendChild(oTemp);
document.onmousemove=function(event){
var event=event||window.event;
var temX=event.clientX-disX;
var temY=event.clientY-disY;
temX=temX>maxLeft?maxLeft:temX;
temX=temX<0?0:temX;
temY=temY>maxTop?maxTop:temY;
temY=temY<0?0:temY;
oTemp.style.left=temX+"px";
oTemp.style.top=temY+"px";
return false;
}
document.onmouseup=function(){
document.onmousemove=null;
document.onmouseup=null;
oBox.style.left=oTemp.style.left;
oBox.style.top=oTemp.style.top;
document.body.removeChild(oTemp);
}
return false;
}
</script>
</html>

考虑到用户交互的移动,这往往是我们真正会做到的东西.

最新文章

  1. Sql语句,先查询再插入一条语句完成。
  2. HDOJ 1875
  3. 时事新闻之 谷歌 google 发布Tensor Flow 源代码
  4. Fastjson反序列化泛型类型时候的一个问题
  5. PI数据库的使用-PI System Management Tools
  6. C++11下的线程池以及灵活的functional + bind + lamda
  7. 给即将面临Noip的二班同学
  8. LeetCode OJ 123. Best Time to Buy and Sell Stock III
  9. 【树莓派】树莓派下WiFi断线自动重连
  10. Unity 打包总结和资源的优化和处理
  11. Cookie实现登录记住密码
  12. Linux守护进程管理利器——Supervisor
  13. 3. Python 字典 常用办法总结
  14. 源码编译安装lnmp环境
  15. Java char
  16. web环境中微信JS-SDK配置
  17. ViewPager中切换界面Fragment被销毁的问题
  18. [sql]mysql5.6cmake安装/mysql5.7二进制安装
  19. Safe point
  20. elementUI和iview兼容么

热门文章

  1. Execl to HTML
  2. 迁移学习-微调(fine-tune)的注意事项:
  3. Cloudera安装要点
  4. BZOJ1206:[HNOI2005]虚拟内存
  5. 人物-IT-刘强东:刘强东
  6. 关于使用sklearn进行数据预处理 —— 归一化/标准化/正则化
  7. java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp区别和联系
  8. cygwin运行git submodule init出错error while loading shared libraries的解决
  9. NMF非负矩阵分解
  10. JWT使用过程中遇到的问题