javascript动画之模拟拖拽效果篇
作者:小火柴的蓝色理想 发布时间:2024-04-16 09:14:22
先看看实现效果图, 模拟拖拽最终效果和在桌面上移动文件夹的效果类似
原理介绍
鼠标按下时,拖拽开始。鼠标移动时,被拖拽元素跟着鼠标一起移动。鼠标抬起时,拖拽结束
所以,拖拽的重点是确定被拖拽元素是如何移动的
假设,鼠标按下时,鼠标对象的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分别用offsetLeft
和offsetTop
表示
鼠标移动时,瞬时态的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>
代码优化
使用上面的代码时,会出现一个问题。当鼠标拖动的太快,比onmousemove
事件的触发间隔还要快时,鼠标就会从元素上离开。这样就停止了元素的拖拽过程
此时,如果把mousemove
和mouseup
事件都加在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>
拖拽冲突
由于文字和图片默认支持原生拖放,如果将原生拖放和模拟拖拽掺杂在一起,将造成与预想效果不符的情况
如果拖放的元素内容存在文字,且文字被选中会触发文字的原生拖放效果
在文字上面双击鼠标,即可选中文字,再移动鼠标时,会触发文字的原生拖放效果,如下所示
只要在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>
总结


猜你喜欢
- 1、什么是归一化:归一化就是把一组数(大于1)化为以1为最大值,0为最小值,其余数据按百分比计算的方法。如:1,2,3.,那归一化后就是:0
- 自动更新统计信息的基本算法是: · 如果表格是在 tempdb 数据库表的基数是小于 6,自动更新到表的每个六个修改。 · 如果表的基数是大
- 我就废话不多说了,大家还是直接看代码吧~<template><uploader :options="option
- 用类和对象实现一个银行账户的资金交易管理, 包括存款、取款和打印交易详情, 交易详情中包含每次交易的时间、存款或者取款的金额、每次交易后的余
- 数据库和操作系统一样,是一个多用户使用的共享资源。当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操
- 在用jupyter notebook写python代码的过程中会产生很多变量,而关闭后或者restart jupyter kernel后所有
- 窗口背景主要包括,背景色与背景图片,设置窗口背景有三种方法使用QSS设置窗口背景使用QPalette设置窗口背景实现PainEvent,使用
- 在这一部分,我们学习创建状态栏,菜单栏和工具栏。一个菜单是位于菜单栏的一组命令。一个工具栏有一些按钮,这些按钮在应用程序中拥有一些常用命令。
- MySQL多表join时报错如下:[Err]1267 – Illegal mix of collations(utf8_general_ci
- 当需要实现html页面部分模块截图并具有保存图片功能时,前台直接生成截图并下载会方便的多。多的不说,直接看代码首先我们需要引入2个js文件:
- 引言webpack插件CommonsChunkPlugin的主要作用是抽取webpack项目入口chunk的公共部分,具体的用法就不做过多介
- 有时候我们会截取字符串中的一些特殊想要的东西,大小写字母、模号、汉字、数字等等,今天先介绍一个获取字符串中小写字母(也是大写字母)的方式,直
- IDE(集成开发环境)或换句话说PHP编辑器是开发人员在构建移动或Web应用必不可少的工具。在这篇文章中,我们将讨论有关PHP编辑器并分享5
- 本文实例介绍了javascript实现九宫格相加数值相等的对应方法,分享给大家供大家参考,具体内容如下实现思路:1、每个格子输入的数值必须为
- 说明1、导入unittest模块。2、导入被测对象。3、创建测试类unittest.TestCase。4、重写setUp和tearDown(
- 众所周知,如果py文件不在当前路径,那么就不能import,因此,本文介绍如下两种有效的方法:方法1:修改环境变量,在~/.bashrc里面
- 这篇文章主要介绍了python文字和unicode/ascll相互转换函数及简单加密解密实现代码,下面我们来了解一下。import reim
- 笔者认为,在创建索引时要做到三个适当,即在适当的表上、适当的列上创建适当数量的索引。虽然这可以通过一句话来概括优化的索引的基本准则,但是要做
- 要想在不宽裕的页面展现丰富的内容,现在通用的做法使用tab,在一块区域通过tab切换来更换该区域的内容。这篇文章分析了tab设计很在理,今天
- 基于Python实现对求解最长回文子串的动态规划算法,具体内容如下1、题目给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的