一、前言:

最近要实现一个元素拖放效果,鼠标拖动元素并且定位元素,首先想到的是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事件模拟元素拖动的更多相关文章

  1. 浅谈Javascript事件模拟

    事件是用来描述网页中某一特定有趣时刻的,众所周知事件通常是在由用户和浏览器进行交互时触发,其实不然,通过Javascript可以在任何时间触发特定的事件,并且这些事件与浏览器创建的事件是相同的.这就意 ...

  2. JavaScript 事件——“模拟事件”的注意要点

    DOM中的事件模拟 三个步骤: 首先通过document.createEvent()方法创建event对象,接收一个参数,即表示要创建的事件类型的字符串: UIEvents(DOM3中的UIEvent ...

  3. 浅谈JavaScript的事件(事件模拟)

    事件经常由操作或者通过浏览器功能触发,通过JavaScript也可以触发元素的事件.通过JavaScript触发事件,也称为事件的模拟. DOM中事件模拟 可以document的createEvent ...

  4. javaScript事件机制深入学习(事件冒泡,事件捕获,事件绑定方式,移除事件方式,阻止浏览器默认行为,事件委托,模拟浏览器事件,自定义事件)

    前言 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软 ...

  5. JavaScript实现元素拖动性能优化

    前言:前几天没事干写了个小网站,打算用原生的javascript实现元素的拖动,但是事情并没有想象的那么顺利,首先是实现了拖动的元素卡的不能再卡,简直不能够,上图~~ 看见没?这就是效果,简直让人欲哭 ...

  6. javascript和jquery 获取触发事件的元素

    一个很简单的问题,却因为大意,经常忘了处理,导致程序运行出错. <!DOCTYPE html> <html> <head> <meta charset=&qu ...

  7. Javascript事件模型(二):Javascript事件的父元素和子元素

    DOM事件标准定义了两种事件流,分别是捕获和冒泡.默认情况下,事件使用冒泡事件流,不使用捕获事件流.你可以指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true. ...

  8. Javascript高级编程学习笔记(72)—— 模拟事件(2)IE事件模拟

    IE中的事件模拟 低版本的IE浏览器作为前端开发的一股清流,想避过都不行 虽然低版本IE正在逐步被市场淘汰,不得不承认IE8以下的浏览器依然占了不小的份额 所以这里大概介绍IE8以下的低版本IE中的事 ...

  9. Javascript高级编程学习笔记(71)—— 模拟事件(1)DOM事件模拟

    事件,指的是网页中某个特定的交互时刻 一般来说事件由浏览器厂商负责提供,一般由用户操作或者其它浏览器功能来触发 但是有一类特殊的事件,那就是由我们开发人员通过JS触发的事件 这些事件和浏览器创建的事件 ...

随机推荐

  1. Accer 4752G添加固态硬盘 双系统

    (此文一直在草稿箱里躺了一年,略作修改后发布~) 背景:电脑是2011年年末买的,用到现在也已经5年多了,好在没坏过什么硬件,有过2年疯狂打LOL的经历,之后电脑就打不动了,FPS始终上不去,启动游戏 ...

  2. 《杜增强讲Unity之Tanks坦克大战》10-相机控制

    10 相机控制 本节主要学习如何控制相机自动调整位置和焦距,使两个坦克一直同时在视野内.   image 在Hierarchy点击右键   image 点击 Create Empty,生成空对象,改名 ...

  3. Celery基本使用

    Celery 什么是Celery? Celery是一种简单/高效/灵活的即插即用的分布式任务队列. Celery应用场景? 需要异步处理的任务,发邮件/发短信/上传等耗时的操作.最终到达提升用户体验的 ...

  4. webpack4-用之初体验,一起敲它十一遍

    众所周知,webpack进入第4个大版本已经有2个月的时间了,而且webpack团队升级更新的速度也是非常的惊人 在写下如下内容的时候webpack已经出到了4.6的版本了,剑指5.0应该是指日可待了 ...

  5. PAT甲题题解-1055. The World's Richest (25)-终于遇见一个排序的不水题

    题目简单,但解题的思路需要转换一下,按常规思路肯定超时,推荐~ 题意:给出n个人的姓名.年龄和拥有的钱,然后进行k次查询,输出年龄在[amin,amx]内的前m个最富有的人的信息.如果财富值相同就就先 ...

  6. M1阶段事后总结

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述?我们组要爬取网上的内容供下一组使用,定义的不太清楚,因为用户只有下一个团队所以没有进行详细的需求分析 ...

  7. js页面实时显示时间

    1.通过getMonth()实现获取月份,从0开始计数,需要+1: 2.通过getDay()实现获取星期天数,从0开始,0表示星期日: 3.通过getDate()获取日期. 4.setTimeout( ...

  8. Struts2 调用非execute方法

    调用非execute方法 1)如果你的Action类是继承自ActionSupport的话,确切的说是重写了execute方法,ActionSupport里的默认实现就是返回"success ...

  9. week4

    History:Commercialization and Growth course Explosive Growth of the Internet and Web The Year of the ...

  10. PAT 甲级 1110 Complete Binary Tree

    https://pintia.cn/problem-sets/994805342720868352/problems/994805359372255232 Given a tree, you are ...