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 相关文章推荐
JavaScript XML实现两级级联下拉列表
Nov 10 Javascript
js 页面输出值
Nov 30 Javascript
Extjs学习笔记之五 一个小细节renderTo和applyTo的区别
Jan 07 Javascript
Javascript 函数parseInt()转换时出现bug问题
May 20 Javascript
js动态改变select选择变更option的index值示例
Jul 10 Javascript
jQuery实现灰蓝风格标准二级下拉菜单效果代码
Aug 31 Javascript
js利用for in循环获取 一个对象的所有属性以及值的实例
Mar 30 Javascript
浅谈Express异步进化史
Sep 09 Javascript
Vue 父子组件的数据传递、修改和更新方法
Mar 01 Javascript
Vue组件实现触底判断
Jun 26 Javascript
ES6 Generator基本使用方法示例
Jun 06 Javascript
Node 使用express-http-proxy 做api网关的实现
Oct 15 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/05/07 PHP
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
ThinkPHP3.1新特性之查询条件预处理简介
2014/06/19 PHP
PHP错误Warning: Cannot modify header information - headers already sent by解决方法
2014/09/27 PHP
Thinkphp中的curd应用实用要点
2015/01/04 PHP
浅析php如何实现App常用的秒发功能
2016/08/03 PHP
php实现等比例不失真缩放上传图片的方法
2016/11/14 PHP
php面向对象程序设计入门教程
2019/06/22 PHP
javascript 页面划词搜索JS
2009/09/28 Javascript
jQuery检测某个元素是否存在代码分享
2015/07/09 Javascript
JS判断浏览器是否安装flash插件的简单方法
2016/09/13 Javascript
Javascript 链式作用域详细介绍
2017/02/23 Javascript
JavaScript+Canvas实现彩色图片转换成黑白图片的方法分析
2018/07/31 Javascript
js中获取URL参数的共用方法getRequest()方法实例详解
2018/10/24 Javascript
sharp.js安装过程中遇到的问题总结
2020/04/02 Javascript
微信公众号中的JSSDK接入及invalid signature等常见错误问题分析(全面解析)
2020/04/11 Javascript
vue 使用class创建和清除水印的示例代码
2020/12/25 Vue.js
Python中用Decorator来简化元编程的教程
2015/04/13 Python
Python中操作文件之write()方法的使用教程
2015/05/25 Python
Windows下Python2与Python3两个版本共存的方法详解
2017/02/12 Python
python获取时间及时间格式转换问题实例代码详解
2018/12/06 Python
twilio python自动拨打电话,播放自定义mp3音频的方法
2019/08/08 Python
django和vue实现数据交互的方法
2019/08/21 Python
基于python实现把图片转换成素描
2019/11/13 Python
浅谈Django中的QueryDict元素为数组的坑
2020/03/31 Python
写一个在SQL Server创建表的SQL语句
2012/03/10 面试题
说说在weblogic中开发消息Bean时的persistent与non-persisten的差别
2013/04/07 面试题
应聘医学检验人员自荐信
2013/09/27 职场文书
《猴子种树》教学反思
2014/02/14 职场文书
2014学校庆三八妇女节活动总结
2014/03/01 职场文书
公司寄语大全
2014/04/10 职场文书
人事专员岗位职责
2015/02/03 职场文书
2015年七夕情人节感言
2015/08/03 职场文书
Python编解码问题及文本文件处理方法详解
2021/06/20 Python
Python绘画好看的星空图
2022/03/17 Python
解决vue-router的beforeRouteUpdate不能触发
2022/04/14 Vue.js