Js元素拖拽功能实现
- Js元素拖拽功能实现
需要解决的问题
最近项目遇到了一个问题,就是用户某个操作需要弹出一个自定义的内容输入框,但是有个缺点,当浏览太大的时候没办法点击确认和取消按钮,应为这个弹出框是采用绝对定位的,取消和确认按钮都被挡住了。
拖拽的原理及实现
首先将元素设置为绝对定位,还用到鼠标的三个事件(mousedown、mousemove和mouseup),当用户按下鼠标触发mousedown事件设置被拖拽的元素为拖拽对象,然后移动鼠标连续触发mousemove事件,判断拖拽对象不为空时重新设置拖拽对象的位置,直到松开触发mouseup事件将拖拽对象置空。
遇到的问题
消抖问题:
刚开始没有计算元素的坐标与点击事件位置之间的差值,直接将鼠标移动的位置赋值给元素的位置(top和left属性),这样用户会感觉到鼠标跳动了一下,并且随着鼠标的移动,元素一直在鼠标的右下方。
这个问题的解决办法是:在触发mousedown的时候除了设置被拖拽的事件,也要记录拖拽对象的位置与事件发生的位置的水平和垂直之间的差值,触发mousemove事件的时候将拖拽对象的位置设置为事件发生的水平和垂直位置对应减去差值。
设计问题
本想尝试着为处理事件的函数传入一个参数(dom对象或者jQuery对象),为这个参数添加拖动事件(三个鼠标监听事件),但是效果不好,触发mouseup的时候有问题,后来将mouseup事件放在了document上,这样又发现了之前未发现的问题,在任何地方都可以触发拖动事件让元素被拖动,这样也不好。
源代码:
function dragEvent:(ele){
var drag = null,
diffx = 0,
diffy = 0,
$e = null;
if($.isNull(ele)) return;
if(!($e = $(ele))) return;
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
//$(document).bind("mouseup",handleEvent);
$.muphy.addEevent(document,"mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = $e[0];
switch(event.type){
case "mousedown":
if($.Nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
}
break;
case "mouseup":
drag = null;
break;
}
}
}
效果好的解决方案
除了设置被拖动的元素为绝对定位之外,再为其添加一个类class=”draggable”,不需要给拖拽事件传入元素,将拖动事件的三个鼠标监听事件都放在document上,当触发mousedown事件时判断目标元素上是否有draggable类,有的话就将这个元素赋值给拖动对象,其他鼠标事件不变。
这个方式有一点需要注意,当拖动对象有内容的时候要为其设置padding属性以便能在边缘触发拖动事件。
源代码:
function dragEvent1(){
var drag = null,
diffx = 0,
diffy = 0;
$(document).unbind("mousedown",handleEvent);
$(document).unbind("mousemove",handleEvent);
$(document).unbind("mouseup",handleEvent);
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
$(document).bind("mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = event.target || event.srcElement;
switch(event.type){
case "mousedown":
if($.nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
}
break;
case "mouseup":
drag = null;
break;
}
}
}
为拖放添加自定义事件
为拖动事件添加三个事件:dragstart、drag和dragend,分别表示拖动开始,正在拖动,拖动结束。
源代码:
function dragEvent() {
var drag = null,
ce = new muphy.costomEvent();
diffx = 0,
diffy = 0;
$(document).unbind("mousedown", handleEvent);
$(document).unbind("mousemove", handleEvent);
$(document).unbind("mouseup", handleEvent);
$(document).bind("mousedown", handleEvent);
$(document).bind("mousemove", handleEvent);
$(document).bind("mouseup", handleEvent);
function handleEvent(event) {
event = event || window.event;
var target = event.target || event.srcElement;
switch (event.type) {
case "mousedown":
if ($m.nvl(target.className).indexOf("draggable") > -1) {
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
event.type = "dragstart";
ce.fire(event)
}
break;
case "mousemove":
if (drag !== null) {
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
event.type = "drag";
ce.fire(event)
}
break;
case "mouseup":
if (drag != null) {
drag = null;
event.type = "dragend";
ce.fire(event)
}
break;
}
}
return ce;
}
有一个小问题就是:当在某个父节点阻止了鼠标的mousedown、mousemove和mouseup事件的时候,拖放不能正常运行。
附件:
封装的所有代码(muphy-common.js):
(function(window,$){
var muphy = Object.create({
isNull: function(data){
if(data === null || data === undefined){
return true;
}
if( typeof data === "String" && data.trim() ==='' ){
return true;
}
if(data instanceof Array && data.length == 0){
return true;
}
return false;
},
nvl: function(data,obj){
if(obj === 0) return 0;
return data || obj || '';
},
each: function(obj,fun){
for (var key in obj) {
if(fun.call(obj[key], key, obj[key]) === false){
break;
}
}
},
addEvent: function(ele,type,handler){
if(ele.addEventListener){
ele.addEventListener(type,handler,false);
} else if(ele.attachEvent){
ele.attachEvent("on" + type, handler);
} else {
ele["on" + type] = handler;
}
},
removeEvent: function(ele,type,handler){
if(ele.removeEventListener){
ele.removeEventListener(type,handler,false);
} else if(ele.detachEvent){
ele.detachEvent("on" + type, handler);
} else {
ele["on" + type] = null;
}
},
_dragEvent: function(ele){
var drag = null,
diffx = 0,
diffy = 0,
$e = null;
if($.isNull(ele)) return;
if(!($e = $(ele))) return;
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
//$(document).bind("mouseup",handleEvent);
$.muphy.addEevent(document,"mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = $e[0];
switch(event.type){
case "mousedown":
if($m.nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
}
break;
case "mouseup":
drag = null;
break;
}
}
},
dragEvent: function(){
var drag = null,
ce = new muphy.costomEvent();
diffx = 0,
diffy = 0;
$(document).unbind("mousedown",handleEvent);
$(document).unbind("mousemove",handleEvent);
$(document).unbind("mouseup",handleEvent);
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
$(document).bind("mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = event.target || event.srcElement;
switch(event.type){
case "mousedown":
if($m.nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
event.type = "dragstart";
ce.fire(event)
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
event.type = "drag";
ce.fire(event)
}
break;
case "mouseup":
if(drag != null){
drag = null;
event.type = "dragend";
ce.fire(event)
}
break;
}
}
return ce;
},
_costomEvent: function(){
var handlers = {};
this.addEvent = function(type, handler){
if(typeof handlers[type] === 'undefined'){
handlers[type] = [];
}
handlers[type].push(handler);
}
this.removeEvent = function(type, handler){
if(handlers[type] instanceof Array){
muphy.each(handlers[type], function(i){
if(this === handler){
handlers[type].splice(i,1);
return false;
}
});
}
}
this.fire = function(event){
if(!event.target){
event.target = this;
}
if(handlers[event.type] instanceof Array){
muphy.each(handlers[event.type],function(){
this(event);
})
}
}
},
costomEvent: function(){}
});
(function(muphy){
muphy.costomEvent.prototype = {
constructor: muphy.costomEvent1,
handlers:{},
addEvent: function(type, handler){
if(typeof this.handlers[type] === 'undefined'){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
removeEvent: function(type, handler){
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
muphy.each(handlers, function(i){
if(this === handler){
handlers.splice(i,1);
return false;
}
});
}
},
fire: function(event){
if(!event.target){
event.target = this;
}
if(this.handlers[event.type] instanceof Array){
muphy.each(this.handlers[event.type],function(){
this(event);
})
}
}
}
})(muphy);
window.$m = muphy;
})(window,jQuery);
以下是测试代码
<!DOCTYPE html>
<html>
<head>
<title>拖动事件处理</title>
<script type="text/javascript" src='./jquery.js'></script>
<script type="text/javascript" src='./Event.js'></script>
</head>
<body>
<div>
<div id="draggable" class="draggable"
style="position: relative;width: 200px;height:100px;left: 300px;top: 200px;border: 1px solid red">
<p style="border: 1px solid green">
<span>哈哈哈哈哈</span>
</p>
</div>
</div>
</body>
<script type="text/javascript">
(function (window, $) {
var d = $m.dragEvent();
var fun = function (e) {
console.log(e.type);
}
d.addEvent("dragstart", fun);
d.addEvent("dragend", function () {
alert(123);
});
d.addEvent("dragend", fun);
d.removeEvent("dragend", fun);
// d.ennable1("#draggable")
})(window, $)
</script>
</html>
Js元素拖拽功能实现的更多相关文章
- JS实现拖拽功能
本文代码地址(第一节):https://github.com/dirstart/js-exam/blob/master/%E6%8B%96%E6%8B%BDdiv1.html 第二节:https:// ...
- 原生js实现拖拽功能
1. 给个div,给定一些样式 <div class="drag" style="left:0;top:0;width:100px;height:100px&quo ...
- 通过 JS 实现简单的拖拽功能并且可以在特定元素上禁止拖拽
前言 关于讲解 JS 的拖拽功能的文章数不胜数,我确实没有必要大费周章再写一篇重复的文章来吸引眼球.本文的重点是讲解如何在某些特定的元素上禁止拖拽.这是我在编写插件时遇到的问题,其实很多插件的拖拽功能 ...
- 原生js拖拽功能制作滑动条实例教程
拖拽属于前端常见的功能,很多效果都会用到js的拖拽功能.滑动条的核心功能也就是使用js拖拽滑块来修改位置.一个完整的滑动条包括 滑动条.滑动痕迹.滑块.文本 等元素,先把html代码写出来,如下所示: ...
- 关于 JS 拖拽功能的冲突问题及解决方法
前言 我在之前写过关于 JS 拖拽的文章,实现方式和网上能搜到的方法大致相同,别无二致,但是在一次偶然的测试中发现,这种绑定事件的方式可能会和其它的拖拽事件产生冲突,由此产生了对于事件绑定的思考.本文 ...
- js进阶 12-17 jquery实现鼠标左键按下拖拽功能
js进阶 12-17 jquery实现鼠标左键按下拖拽功能 一.总结 一句话总结:监听的对象必须是文档,鼠标按下运行mousemove事件,鼠标松开取消mousemove事件的绑定,div的偏移的话是 ...
- (Demo分享)利用JavaScript(JS)实现一个九宫格拖拽功能
利用JavaScript(JS)实现一个九宫格拖拽功能 Demo实现了对任意方格进行拖拽,可以交换位置,其中Demo-1利用了勾股定理判断距离! Demo-1整体思路: 1.首先div实现自由移动 ...
- vuejs2.0使用Sortable.js实现的拖拽功能
简介 在使用vue1.x之前的版本的时候,页面中的拖拽功能,我在项目中是直接用的jquery ui中的sortable.js,只是在拖拽完成后,在update的回调函数中又重新排序了存放数据的数组.但 ...
- js 鼠标拖拽元素
基础知识 event.clientX.event.clientY 鼠标相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条.IE事件和标准事件都定义了这2个属性 event. ...
随机推荐
- 十分钟(小时)学习pandas
十分钟学习pandas 一.导语 这篇文章从pandas官网翻译:链接,而且也有很多网友翻译过,而我为什么没去看他们的,而是去官网自己艰难翻译呢? 毕竟这是一个学习的过程,别人写的不如自己写的记忆深刻 ...
- linux备份还原命令
使用范围:1.可以作为系统还原点,还原到备份时的状态 2.系统完全损坏后无法启动,通过引导盘恢复 一.备份还原系统命令 方法一: 备份:tar cvpzf backup.tgz --exclude=/ ...
- MySQL从查找数据库表到删除全过程
使用DOS命令进入MySQL:mysql -u root -p 按回车键输入密码显示如下界面成功进入MySQL交互界面. 如果此时不知道MySQL有哪些数据库,使用显示所有数据库名语句:show ...
- 雨后清风教你如何在Windows 7中对硬盘进行分区
磁盘分区是将硬盘驱动器分成多个逻辑单元.人们通常不会选择对硬盘进行分区,但它有很多好处.主要是,通过对磁盘进行分区,您可以将操作系统与数据分开,从而减少数据损坏的可能性. 磁盘分区方法 打开“计算机管 ...
- Python Docker 查看私有仓库镜像【转】
文章来源:python Docker 查看私有仓库镜像 pip 安装: # 首先安装epel扩展源: yum -y install epel-release # 更新完成之后,就可安装pip: yum ...
- LeetCode算法题-Design HashSet(Java实现)
这是悦乐书的第298次更新,第317篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第166题(顺位题号是705).不使用任何内建的hash表库设计一个hash集合,应包含 ...
- 我的第一个python web开发框架(23)——代码版本控制管理与接口文档
书接上一回,小白和老菜聊到代码的版本控制和接口文档 小白:为什么要做版本控制,我不弄版本控制不也完成了项目了吗?要做版本控制不是很麻烦,又要安装服务又要提交代码,代码又不是多人用开发,还要写文档... ...
- 使用Visual Studio Code进行ABAP开发
长期以来,我们都使用SAP GUI进行ABAP编码工作,事务代码SE38甚至成了ABAP的代名词. SAP GUI的代码编辑能力和一些专业的IDE比较起来难免相形见绌,为了给开发者们更好的体验,SAP ...
- 戏说春秋_i春秋 writeup
<戏说春秋>第一关 图穷匕见 题目: 解:用winhex打开,拉到最后可发现一段编码 放到解密网站上解码. <戏说春秋>第二关 纸上谈兵 解:文中没有明确指出问题,也没有给出线 ...
- 怎样保证socket.recv接收完数据
最近在使用python进行网络编程开发一个通用的tcpclient测试小工具.在使用socket进行网络编程中,如何判定对端发送一条报文是否接收完成,是进行socket网络开发必须要考虑的一个问题.这 ...