javascript动画之模拟拖拽效果篇


Posted in Javascript onSeptember 26, 2016

先看看实现效果图, 模拟拖拽最终效果和在桌面上移动文件夹的效果类似

javascript动画之模拟拖拽效果篇

原理介绍

鼠标按下时,拖拽开始。鼠标移动时,被拖拽元素跟着鼠标一起移动。鼠标抬起时,拖拽结束

所以,拖拽的重点是确定被拖拽元素是如何移动的

javascript动画之模拟拖拽效果篇

假设,鼠标按下时,鼠标对象的clientX和clientY分别为x1和x2。元素距离视口左上角x轴和y轴分别为x0和y0

鼠标移动的某一时刻,clientX和clientY分别为x2和y2

所以,元素移动的x轴和y轴距离分别为x2-x1和y2-y1

元素移动后,元素距离视口左上角x轴和y轴的位置分别为

X = x0 + (x2-x1)
 Y = y0 + (y2-y1)

代码实现

将上面的原理用代码实现如下

鼠标按下时,初始态的x0和y0分别用offsetLeftoffsetTop表示

鼠标移动时,瞬时态的x和y分别赋值为定位后元素的left和top

<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;"></div>
<script>
test.onmousedown = function(e){
 e = e || event;
 //获取元素距离定位父级的x轴及y轴距离
 var x0 = this.offsetLeft;
 var y0 = this.offsetTop;
 //获取此时鼠标距离视口左上角的x轴及y轴距离
 var x1 = e.clientX;
 var y1 = e.clientY;

 test.onmousemove = function(e){
  e = e || event;
  //获取此时鼠标距离视口左上角的x轴及y轴距离
  x2 = e.clientX;
  y2 = e.clientY; 
  //计算此时元素应该距离视口左上角的x轴及y轴距离
  var X = x0 + (x2 - x1);
  var Y = y0 + (y2 - y1);
  //将X和Y的值赋给left和top,使元素移动到相应位置
  test.style.left = X + 'px';
  test.style.top = Y + 'px';
 }

 test.onmouseup = function(e){
  //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
  test.onmousemove = null;
 }
}
</script>

javascript动画之模拟拖拽效果篇

代码优化

使用上面的代码时,会出现一个问题。当鼠标拖动的太快,比onmousemove事件的触发间隔还要快时,鼠标就会从元素上离开。这样就停止了元素的拖拽过程

此时,如果把mousemovemouseup事件都加在document上时,即可解决

<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;"></div>
<script>
test.onmousedown = function(e){
 e = e || event;
 //获取元素距离定位父级的x轴及y轴距离
 var x0 = this.offsetLeft;
 var y0 = this.offsetTop;
 //获取此时鼠标距离视口左上角的x轴及y轴距离
 var x1 = e.clientX;
 var y1 = e.clientY;

 document.onmousemove = function(e){
  e = e || event;
  //获取此时鼠标距离视口左上角的x轴及y轴距离
  x2 = e.clientX;
  y2 = e.clientY; 
  //计算此时元素应该距离视口左上角的x轴及y轴距离
  var X = x0 + (x2 - x1);
  var Y = y0 + (y2 - y1);
  //将X和Y的值赋给left和top,使元素移动到相应位置
  test.style.left = X + 'px';
  test.style.top = Y + 'px';
 }

 document.onmouseup = function(e){
  //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
  document.onmousemove = null;
 }
}
</script>

javascript动画之模拟拖拽效果篇

拖拽冲突

由于文字和图片默认支持原生拖放,如果将原生拖放和模拟拖拽掺杂在一起,将造成与预想效果不符的情况

如果拖放的元素内容存在文字,且文字被选中会触发文字的原生拖放效果

在文字上面双击鼠标,即可选中文字,再移动鼠标时,会触发文字的原生拖放效果,如下所示

javascript动画之模拟拖拽效果篇

只要在onmousedown事件阻止浏览器的默认行为即可

<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">测试文字</div>
<script>
test.onmousedown = function(e){
 e = e || event;
 //获取元素距离定位父级的x轴及y轴距离
 var x0 = this.offsetLeft;
 var y0 = this.offsetTop;
 //获取此时鼠标距离视口左上角的x轴及y轴距离
 var x1 = e.clientX;
 var y1 = e.clientY;

 document.onmousemove = function(e){
  e = e || event;
  //获取此时鼠标距离视口左上角的x轴及y轴距离
  x2 = e.clientX;
  y2 = e.clientY; 
  //计算此时元素应该距离视口左上角的x轴及y轴距离
  var X = x0 + (x2 - x1);
  var Y = y0 + (y2 - y1);
  //将X和Y的值赋给left和top,使元素移动到相应位置
  test.style.left = X + 'px';
  test.style.top = Y + 'px';
 }

 document.onmouseup = function(e){
  //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
  document.onmousemove = null;
 }
 //阻止默认行为
 return false;
}
</script>

IE兼容

以上代码在IE8-浏览器中仍然无法阻止默认行为。此时,为了实现IE兼容,需要使用全局捕获setCapture()和释放捕获releaseCapture()

首先,先看一下全局捕获的效果

下面代码中,开启全局捕获之后,页面中的所有点击效果,都相当于针对按钮一的点击效果。释放捕获后,效果消失

[注意]IE浏览器完全支持全局捕获;chrome不支持,使用全局捕获会报错;firefox不报错,但静默失败

<button id="btn1">按钮一</button>
<button id="btn2">开启按钮一的全局捕获</button>
<script>
btn1.onclick = function(){
 alert(1);
}
btn2.onclick = function(){
 if(btn1.setCapture){
  if(btn2.innerHTML.charAt(0) == '开'){
   btn1.setCapture();
   btn2.innerHTML = '关闭按钮一的全局捕获';
  }else{
   btn1.releaseCapture();
   btn2.innerHTML = '开启按钮一的全局捕获'; 
  }
 }
}
</script>

通过在IE浏览器设置全局捕获来达到取消文字原生拖放的默认行为

<div id="test" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">测试文字</div>
<script>
test.onmousedown = function(e){
 e = e || event;
 //获取元素距离定位父级的x轴及y轴距离
 var x0 = this.offsetLeft;
 var y0 = this.offsetTop;
 //获取此时鼠标距离视口左上角的x轴及y轴距离
 var x1 = e.clientX;
 var y1 = e.clientY;

 document.onmousemove = function(e){
  e = e || event;
  //获取此时鼠标距离视口左上角的x轴及y轴距离
  x2 = e.clientX;
  y2 = e.clientY; 
  //计算此时元素应该距离视口左上角的x轴及y轴距离
  var X = x0 + (x2 - x1);
  var Y = y0 + (y2 - y1);
  //将X和Y的值赋给left和top,使元素移动到相应位置
  test.style.left = X + 'px';
  test.style.top = Y + 'px';
 }

 document.onmouseup = function(e){
  //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
  document.onmousemove = null;
  //释放全局捕获
  if(test.releaseCapture){
   test.releaseCapture();
  }
 }
 //阻止默认行为
 return false;
 //IE8-浏览器阻止默认行为
 if(test.setCapture){
  test.setCapture();
 }
}
</script>

javascript动画之模拟拖拽效果篇

总结

以上就是Javascript模拟拖拽的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
jQuery 处理网页内容的实现代码
Feb 15 Javascript
JavaScript高级程序设计 XML、Ajax 学习笔记
Sep 10 Javascript
弹出窗口并且此窗口带有半透明的遮罩层效果
Mar 13 Javascript
js点击列表文字对应该行显示背景颜色的实现代码
Aug 05 Javascript
BootStrap实现树形目录组件代码详解
Jun 21 Javascript
three.js实现围绕某物体旋转
Jan 25 Javascript
关于jQuery.ajax()的jsonp碰上post详解
Jul 02 jQuery
仿淘宝JSsearch搜索下拉深度用法
Jan 15 Javascript
vue写一个组件
Apr 09 Javascript
Layui数据表格 前后端json数据接收的方法
Sep 19 Javascript
js实现简单的无缝轮播效果
Sep 05 Javascript
在vue中给后台接口传的值为数组的格式代码
Nov 12 Javascript
微信小程序(应用号)简单实例应用及实例详解
Sep 26 #Javascript
微信小程序 框架详解及实例应用
Sep 26 #Javascript
jQuery中JSONP的两种实现方式详解
Sep 26 #Javascript
javascript的函数劫持浅析
Sep 26 #Javascript
JavaScript中this的四个绑定规则总结
Sep 26 #Javascript
jQuery 选择器(61种)整理总结
Sep 26 #Javascript
jQuery tagsinput在h5邮件客户端中应用详解
Sep 26 #Javascript
You might like
在字符串指定位置插入一段字符串的php代码
2010/02/16 PHP
如何解决CI框架的Disallowed Key Characters错误提示
2013/07/05 PHP
PHP文件上传之多文件上传的实现思路
2016/01/27 PHP
PHP读取、解析eml文件及生成网页的方法示例
2017/09/04 PHP
JavaScript去除空格的几种方法
2006/10/03 Javascript
js滚动条回到顶部的代码
2011/12/06 Javascript
JavaScript 创建运动框架的实现代码
2013/05/08 Javascript
jquery的ajax和getJson跨域获取json数据的实现方法
2014/02/04 Javascript
Javascript中的关键字和保留字整理
2014/10/16 Javascript
jQuery操作dom实现弹出页面遮罩层(web端和移动端阻止遮罩层的滑动)
2016/08/25 Javascript
vue指令以及dom操作详解
2017/03/04 Javascript
Bootstrap Table从零开始
2017/06/30 Javascript
vue-cli 3 全局过滤器的实例代码详解
2019/06/03 Javascript
JS实现的对象去重功能示例
2019/06/04 Javascript
webpack 处理CSS资源的实现
2019/09/27 Javascript
JS求解两数之和算法详解
2020/04/28 Javascript
python redis连接 有序集合去重的代码
2019/08/04 Python
python cv2截取不规则区域图片实例
2019/12/21 Python
python+opencv实现移动侦测(帧差法)
2020/03/20 Python
Python如何合并多个字典或映射
2020/07/24 Python
关于多种方式完美解决Python pip命令下载第三方库的问题
2020/12/21 Python
科颜氏加拿大官方网站: Kiehl’s加拿大
2016/08/16 全球购物
戴尔英国官网:Dell英国
2017/05/27 全球购物
Trunki英国官网:儿童坐骑式行李箱
2017/05/30 全球购物
中国首家奢侈品O2O网购平台:第五大道奢侈品网
2017/12/14 全球购物
维多利亚的秘密官方旗舰店:VICTORIA’S SECRET
2018/04/02 全球购物
丝芙兰加拿大官方网站:SEPHORA加拿大
2018/11/20 全球购物
计算机专业个人简短的自我评价
2013/10/23 职场文书
会计电算化毕业生自荐信
2014/03/03 职场文书
工厂门卫岗位职责范本
2014/04/04 职场文书
关于环保的建议书
2014/05/12 职场文书
高效课堂标语
2014/06/26 职场文书
爱护公共设施演讲稿
2014/09/13 职场文书
Mysql 如何批量插入数据
2021/04/06 MySQL
HTML5 新增内容和 API详解
2021/11/17 HTML / CSS
公历12个月名称的由来
2022/04/12 杂记