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触发的事件 这些事件和浏览器创建的事件 ...
随机推荐
- 4星|《流量池》:Luckin Coffee营销操盘手经验谈
流量池:“急功近利”的流量布局.营销转化 作者是一线营销操盘手,全书是作者的经验总结,这样的作者在营销类图书中比较罕见,因此这本书非常有价值. 全书是写给巨头之外的企业营销人员看的,这样的企业的流量来 ...
- 关于k8s这项大动作,预示着边缘计算迎来“开源”发展的新周期……
在文章<最近在边缘计算领域,发生了一件足以载入物联网史册的大事…>我曾经提到Kubernetes(简称K8s)将从超大规模云计算环境,被带入到物联网边缘计算场景中. 事情有了新进展,从本周 ...
- Android Studio发布Release版本之坑--Unknown host 'd29vzk4ow07wi7.cloudfront.net'
使用Android Studio发布Release版本时,出现Unknown host 'd29vzk4ow07wi7.cloudfront.net'...错误. 解决方法:修改本机的DNS为8.8. ...
- PAT甲题题解-1056. Mice and Rice (25)-模拟题
有n个老鼠,第一行给出n个老鼠的重量,第二行给出他们的顺序.1.每一轮分成若干组,每组m个老鼠,不能整除的多余的作为最后一组.2.每组重量最大的进入下一轮.让你给出每只老鼠最后的排名.很简单,用两个数 ...
- 链家鸟哥:从留级打架问题学生到PHP大神,他的人生驱动力竟然是?
链家鸟哥:从留级打架问题学生到PHP大神,他的人生驱动力竟然是?| 二叉树短视频 http://mp.weixin.qq.com/s/D4l_zOpKDakptCM__4hLrQ 从问题劝退学生到高考 ...
- mybatis mapper使用记录
insert://插入一条数据//支持Oracle序列,UUID,类似Mysql的INDENTITY自动增长(自动回写)//优先使用传入的参数值,参数值空时,才会使用序列.UUID,自动增长int i ...
- 《Linux内核分析》 第一节 计算机是如何工作的
第一节 计算机是如何工作的 张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 ...
- (Alpha)Let's-Chronos分数分配规则
Requirement: 每个团队开一个讨论会,协商讨论团队贡献分的分配方式.每个团队的团队贡献分为50分/人.每个人分数不能相同,请详细说明分数的分配规则. 为了完成此次的团队贡献分的分配任务,我们 ...
- 老李的blog使用日记(3)
匆匆忙忙.碌碌无为,这是下一个作业,VS,多么神圣高大上,即使这样,有多少人喜欢你就有多少人烦你,依然逃不了被推销的命运,这抑或是它喜欢接受的,但是作为被迫接受者,能做的的也只有接受,而已. 既来之则 ...
- Beta冲刺——day7
Beta冲刺--day7 作业链接 Beta冲刺随笔集 github地址 团队成员 031602636 许舒玲(队长) 031602237 吴杰婷 031602220 雷博浩 031602134 王龙 ...