JavaScript事件模拟元素拖动
一、前言:
最近要实现一个元素拖放效果,鼠标拖动元素并且定位元素,首先想到的是HTML5中的拖放,在HTML5中,有一个draggable属性,且有dragstart, dragover, drop等事件,主要是通过event.dataTransfer对象方法,在dragstart事件中设置数据event.dataTransfer.setData(); 在drop事件中获取数据event.dataTransfer.getData();但是它并不能实现元素的实时拖放效果,因此还是需要用鼠标事件来模拟元素的拖放。
二、实例示图
三、实现原理:
1、思路:鼠标依次触发mousedown, mousemove, mouseup事件,在mousemove事件中实时计算元素新位置并且定位元素,
在mouseup事件中注销mousemove,mouseup事件。
2、重点:如果所有事件都绑定在拖动元素上,当鼠标移动速度很快,以至于离开了拖动的元素,那么就不会执行mousemove,
mouseup事件处理程序,因此要想让mousemove,mouseup事件处理实时执行,必须将它们绑定到document元素上;
四、插件源码:
$.fn.extend({
/**
*
* 扩展jQuery原型,实现鼠标事件模拟元素拖动
* drag中的回调函数this指向被拖动元素
* @ method: drag
* @ use: $( selector ).drag( dragStart, dragMove, dragEnd )
* @ param { function } 第一个参数,准备拖动处理函数
* @ param { function } 第二个参数,拖动中处理函数
* @ param { function } 第三个参数,拖动结束处理函数
* @ reutrn { jQuery( selector ) }
*
*/
drag: function( dragStart, dragMove, dragEnd ) {
function drag( dragElem, event ) {
var offsetX, offsetY, beforePageX, beforePageY; if ( $.isFunction(dragStart) ) {
dragStart.apply(dragElem, arguments);
} // 移动前或移动中的元素位置
offsetX = parseInt( $(dragElem).css('left'), 10 );
offsetY = parseInt( $(dragElem).css('top'), 10 ); // 移动前或移动中的鼠标位置
beforePageX = event.clientX;
beforePageY = event.clientY; if ( document.addEventListener ) {
document.addEventListener('mousemove', moveHandle, false);
document.addEventListener('mouseup', upHandle, false);
}
else if ( document.attachEvent ) {
dragElem.setCapture(); // 将dragElem鼠标事件继承到文档进行捕获
dragElem.attachEvent('onmousemove', moveHandle);
dragElem.attachEvent('onmouseup', upHandle);
dragElem.attachEvent('onlosecapture', upHandle);
} // 鼠标移动事件处理
function moveHandle (event) {
var event = event || window.event; // 更新移动中或移动终止后的元素位置
var x = offsetX + event.clientX - beforePageX;
var y = offsetY + event.clientY - beforePageY; $(dragElem).css({
left: x + 'px',
top: y + 'px'
}); // 阻止事件传播
if ( event.stopPropagation ){
event.stopPropagation();
}
else if ( event.cancleBubble ) {
event.cancleBubble = true;
} if ( $.isFunction(dragMove) ) {
dragMove.apply(dragElem, arguments);
}
} // 鼠标弹起事件处理
function upHandle (event) {
if ( document.addEventListener ) {
document.removeEventListener('mousemove', moveHandle, false);
document.removeEventListener('mouseup', upHandle, false);
}
else if ( document.detachEvent ) {
dragElem.detachEvent('onlosecapture', upHandle);
dragElem.detachEvent('onmouseup', upHandle);
dragElem.detachEvent('onmousemove', moveHandle);
dragElem.releaseCapture();
}
if ( event.stopPropagation ){
event.stopPropagation();
}
else if ( event.cancleBubble ) {
event.cancleBubble = true;
} if ( $.isFunction(dragEnd) ) {
dragEnd.apply(dragElem, arguments);
}
}
}
$(this).each(function(){
$(this).bind('mousedown', function(e){
var dragElem = this,
event = e;
drag(dragElem, event);
});
});
return this;
}
});
五、调用实例:
(function(){
var dragEnd = false;
$('.drag-elem').drag(
function(){
$(this).text('准备拖动').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });
},
function(){
var offset = $(this).offset();
dragEnd = true;
$(this).text('拖动中(' + offset.left + ',' + offset.top + ')' );
},
function(){
if (dragEnd) {
$(this).text('拖动结束');
dragEnd = false;
}
}
);
}());
六、完整实例代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery drag</title>
<script src="http://code.jquery.com/jquery-1.10.1.js"></script>
<style>
.drag-elem {
position: absolute;
left: 10px;
top: 20px;
z-index: 999;
width: 200px;
height: 50px;
cursor: move;
background-color: #ccc;
border: 5px solid green;
font-size: 24px;
line-height: 50px;
text-align: center;
}
</style>
</head> <body> <div class="drag-elem"></div> <script>
$.fn.extend({
/**
*
* 扩展jQuery原型,实现鼠标事件模拟元素拖动
* drag中的回调函数this指向被拖动元素
* @ method: drag
* @ use: $( selector ).drag( dragStart, dragMove, dragEnd )
* @ param { function } 第一个参数,准备拖动处理函数
* @ param { function } 第二个参数,拖动中处理函数
* @ param { function } 第三个参数,拖动结束处理函数
* @ reutrn { jQuery( selector ) }
*
*/
drag: function( dragStart, dragMove, dragEnd ) {
function drag( dragElem, event ) {
var offsetX, offsetY, beforePageX, beforePageY; if ( $.isFunction(dragStart) ) {
dragStart.apply(dragElem, arguments);
} // 移动前或移动中的元素位置
offsetX = parseInt( $(dragElem).css('left'), 10 );
offsetY = parseInt( $(dragElem).css('top'), 10 ); // 移动前或移动中的鼠标位置
beforePageX = event.clientX;
beforePageY = event.clientY; if ( document.addEventListener ) {
document.addEventListener('mousemove', moveHandle, false);
document.addEventListener('mouseup', upHandle, false);
}
else if ( document.attachEvent ) {
dragElem.setCapture(); // 将dragElem鼠标事件继承到文档进行捕获
dragElem.attachEvent('onmousemove', moveHandle);
dragElem.attachEvent('onmouseup', upHandle);
dragElem.attachEvent('onlosecapture', upHandle);
} // 鼠标移动事件处理
function moveHandle (event) {
var event = event || window.event; // 更新移动中或移动终止后的元素位置
var x = offsetX + event.clientX - beforePageX;
var y = offsetY + event.clientY - beforePageY; $(dragElem).css({
left: x + 'px',
top: y + 'px'
}); // 阻止事件传播
if ( event.stopPropagation ){
event.stopPropagation();
}
else if ( event.cancleBubble ) {
event.cancleBubble = true;
} if ( $.isFunction(dragMove) ) {
dragMove.apply(dragElem, arguments);
}
} // 鼠标弹起事件处理
function upHandle (event) {
if ( document.addEventListener ) {
document.removeEventListener('mousemove', moveHandle, false);
document.removeEventListener('mouseup', upHandle, false);
}
else if ( document.detachEvent ) {
dragElem.detachEvent('onlosecapture', upHandle);
dragElem.detachEvent('onmouseup', upHandle);
dragElem.detachEvent('onmousemove', moveHandle);
dragElem.releaseCapture();
}
if ( event.stopPropagation ){
event.stopPropagation();
}
else if ( event.cancleBubble ) {
event.cancleBubble = true;
} if ( $.isFunction(dragEnd) ) {
dragEnd.apply(dragElem, arguments);
}
}
}
$(this).each(function(){
$(this).bind('mousedown', function(e){
var dragElem = this,
event = e;
drag(dragElem, event);
});
});
return this;
}
});
</script> <script>
(function(){
var dragEnd = false;
$('.drag-elem').drag(
function(){
$(this).text('准备拖动').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });
},
function(){
var offset = $(this).offset();
dragEnd = true;
$(this).text('拖动中(' + offset.left + ',' + offset.top + ')' );
},
function(){
if (dragEnd) {
$(this).text('拖动结束');
dragEnd = false;
}
}
);
}());
</script>
</body>
</html>
源码更新 2014/02/19
$.fn.extend({
/**
*
* 扩展jQuery原型,实现鼠标事件模拟元素拖动
* drag中的回调函数this指向被拖动元素
* @ method: drag
* @ use: $( selector ).drag( dragStartFn, dragMoveFn, dragEndFn )
* @ param { function } 第一个参数,准备拖动处理函数
* @ param { function } 第二个参数,拖动中处理函数
* @ param { function } 第三个参数,拖动结束处理函数
* @ reutrn { jQuery( selector ) }
*
*/
drag: function( dragStartFn, dragMoveFn, dragEndFn ) {
function drag( target, e ) {
var offsetX, offsetY, beforePageX, beforePageY; if ( $.isFunction(dragStartFn) ) {
dragStartFn.apply(target, arguments);
} // 移动前或移动中的元素位置
offsetX = parseInt( $(target).css('left'), 10 ) || 0;
offsetY = parseInt( $(target).css('top'), 10 ) || 0; // 移动前或移动中的鼠标位置
beforePageX = e.clientX;
beforePageY = e.clientY; $(document).bind('mousemove', moveHandle)
.bind('mouseup', upHandle); // 鼠标移动事件处理
function moveHandle (e) {
// 更新移动中或移动终止后的元素位置
var x = offsetX + e.clientX - beforePageX;
var y = offsetY + e.clientY - beforePageY; $(target).css({
left: x + 'px',
top: y + 'px'
});
if ( $.isFunction(dragMoveFn) ) {
dragMoveFn.apply(target, arguments);
}
// 阻止浏览器默认行为(鼠标在拖动图片一小段距离,会出现一个禁止的小提示,即:图片不能再拖动)
e.preventDefault();
} // 鼠标弹起事件处理
function upHandle (e) {
$(document).unbind('mousemove', moveHandle)
.unbind('mouseup', upHandle);
if ( $.isFunction(dragEndFn) ) {
dragEndFn.apply(target, arguments);
}
}
}
$(this).each(function(){
$(this).bind('mousedown', function(e){
drag(this, e);
});
});
return this;
}
}); // 调用实例
(function(){
var dragEnd = false;
$('div').drag(
function(){
$(this).html('<span>准备拖动</span>').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });
},
function(){
var offset = $(this).offset();
$(this).html('<span>拖动中(' + offset.left + ',' + offset.top + ')</span>' );
},
function(){
$(this).html('<span>拖动结束</span>')
}
);
$('img').drag();
}());
JavaScript事件模拟元素拖动的更多相关文章
- 浅谈Javascript事件模拟
事件是用来描述网页中某一特定有趣时刻的,众所周知事件通常是在由用户和浏览器进行交互时触发,其实不然,通过Javascript可以在任何时间触发特定的事件,并且这些事件与浏览器创建的事件是相同的.这就意 ...
- JavaScript 事件——“模拟事件”的注意要点
DOM中的事件模拟 三个步骤: 首先通过document.createEvent()方法创建event对象,接收一个参数,即表示要创建的事件类型的字符串: UIEvents(DOM3中的UIEvent ...
- 浅谈JavaScript的事件(事件模拟)
事件经常由操作或者通过浏览器功能触发,通过JavaScript也可以触发元素的事件.通过JavaScript触发事件,也称为事件的模拟. DOM中事件模拟 可以document的createEvent ...
- javaScript事件机制深入学习(事件冒泡,事件捕获,事件绑定方式,移除事件方式,阻止浏览器默认行为,事件委托,模拟浏览器事件,自定义事件)
前言 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软 ...
- JavaScript实现元素拖动性能优化
前言:前几天没事干写了个小网站,打算用原生的javascript实现元素的拖动,但是事情并没有想象的那么顺利,首先是实现了拖动的元素卡的不能再卡,简直不能够,上图~~ 看见没?这就是效果,简直让人欲哭 ...
- javascript和jquery 获取触发事件的元素
一个很简单的问题,却因为大意,经常忘了处理,导致程序运行出错. <!DOCTYPE html> <html> <head> <meta charset=&qu ...
- Javascript事件模型(二):Javascript事件的父元素和子元素
DOM事件标准定义了两种事件流,分别是捕获和冒泡.默认情况下,事件使用冒泡事件流,不使用捕获事件流.你可以指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true. ...
- Javascript高级编程学习笔记(72)—— 模拟事件(2)IE事件模拟
IE中的事件模拟 低版本的IE浏览器作为前端开发的一股清流,想避过都不行 虽然低版本IE正在逐步被市场淘汰,不得不承认IE8以下的浏览器依然占了不小的份额 所以这里大概介绍IE8以下的低版本IE中的事 ...
- Javascript高级编程学习笔记(71)—— 模拟事件(1)DOM事件模拟
事件,指的是网页中某个特定的交互时刻 一般来说事件由浏览器厂商负责提供,一般由用户操作或者其它浏览器功能来触发 但是有一类特殊的事件,那就是由我们开发人员通过JS触发的事件 这些事件和浏览器创建的事件 ...
随机推荐
- hdu 2036:改革春风吹满地(叉积求凸多边形面积)
改革春风吹满地 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- PWM输出
PWM(Pulse Width Modulation),脉冲宽度调制. 脉冲的频率由ARR控制,ARR越大频率越小:占空比由CCRx控制,CCRx越小占空比越大. 捕获/比较通道的输出部分(通道1) ...
- CentOS7安装OpenStack(Rocky版)-02.安装Keyston认证服务组件(控制节点)
本文分享openstack的认证服务组件keystone --------------- 完美的分割线 ---------------- 2.0.keystone认证服务 1)用户与认证:用户权限与用 ...
- Vue 入门之 Vuex 实战
Vue 入门之 Vuex 实战 引言 Vue 组件化做的确实非常彻底,它独有的 vue 单文件组件也是做的非常有特色.组件化的同时带来的是:组件之间的数据共享和通信的难题. 尤其 Vue 组件设计的就 ...
- “北航Clubs” Beta版本开发目标
Beta版本开发目标 总体设想:修复Alpha版本中的若干bug,并在Alpha版本成果之上进行进一步开发,实现社员管理.评论.站内信等功能. 1.对Alpha版本功能的更新与加强 后端实现从SQLi ...
- SDN交换机迁移2
关于迁移过程中迁移目标(被迁移的交换机和目标控制器)的选择 SDN中基于过程优化的交换机竞争迁移算法 通信学报 交换机:请求速率大于域内平均请求速率的交换机集合: 控制器:综合网络中时延.流量和控制器 ...
- Team Work Ⅱ
Regal-Lighting团队设计 分工思考 本次大作业我的分工定位是:Unit及子类,主要设计实现建筑类的功能. 首先王者光耀这款游戏所需要的建筑分为三类: 1.防御塔:有一定的血量,血量为0时破 ...
- Android开发环境的发展演变调研
Android开发环境的发展演变调研 前几年比较多的方法是用JDK+eclipse+ADT,该方法除了要配置JDK的路径之外, 还要在eclipse里面打开SDK Manage进行相应的操作.不过近两 ...
- image 样式设置
.image-fluid:响应式大小 .image-thumbnails:照片四周会出现一个1px宽的边框 .figure:用于<figure>标签,用来标记一个图像 .figure-ca ...
- JMeter学习笔记——认识JMeter(1)
拿到一个自动化测试工具,我们第一步就应该了解它能提供我们哪方面的功能(最直接的方法就是从官网获取),接下来就是简单的对这个工具进行“功能测试”了,当然这里的功能测试不是让你找它存在的bug,而是让自己 ...