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触发的事件 这些事件和浏览器创建的事件 ...
随机推荐
- nginx location 正则匹配
nginx 统计语句1.根据访问IP统计UV awk '{print $1}' access.log|sort | uniq -c |wc -l2.统计访问URL统计PV awk '{print $7 ...
- (三)Hyperledger Fabric 1.1安装部署-chaincode测试
环境搭建完毕,需要的工具和镜像安装完毕,就可以进行chaincode测试了,接下来参考官方教程运行first-network. 进入first-netwok: cd first-network fir ...
- PAT甲题题解-1117. Eddington Number(25)-(大么个大水题~)
如题,大水题...贴个代码完事,就这么任性~~ #include <iostream> #include <cstdio> #include <algorithm> ...
- java锁经典示例——卖车票场景
场景:20张车票 3个窗口同时售票 1.不加锁 package com.yao.lock; /** * 不加锁的情况 */ public class Runnable_demo implements ...
- 软件工程 BUAAMOOC项目Postmortem结果
设想和目标 1.我们的软件要解决什么问题?是否定义的很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件是基于北航MOOC网站做的Android手机客户端,用于便捷的在学校里通过手机做到随时随地 ...
- [2017BUAA软工助教]个人得分总表(beta阶段)
一.表 学号 b团队 b团队得分 b贡献分 阅读作业 提问回顾 总分 14011100 hotcode5 228 60 6 7.5 301.5 14061213 PM="PokeMon&qu ...
- 第二章:蓝色巨人 IBM公司
COBOL(面向商业的通用语言) DEC(数字设备公司)华生实验室 造成失败的原因: 1,没有经营终端消费型产品 2,技术的流失 3.没有在意对手 成为的方法:合并,保守,谨慎 研究员的工作: 1,发 ...
- 这个C#程序真了不起
(1)在2~31中,这个数不能且仅不能被两个相邻数整除 (2)2 123 581 660 200 (2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,19,20,21,22,2 ...
- Activiti的ACT_GE_PROPERTY表初始化
create table ACT_GE_PROPERTY ( NAME_ ), VALUE_ ), REV_ integer, primary key (NAME_) ) ENGINE=InnoDB ...
- formidable模块的使用
Node.js的Formidable模块的使用 今天总结了下Node.js的Formidable模块的使用,下面做一些简要的说明. 1) 创建Formidable.IncomingForm ...