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. ...
随机推荐
- apply,call和bind的用法区别
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Spring boot入门(二):Spring boot集成MySql,Mybatis和PageHelper插件
上一篇文章,写了如何搭建一个简单的Spring boot项目,本篇是接着上一篇文章写得:Spring boot入门:快速搭建Spring boot项目(一),主要是spring boot集成mybat ...
- 基础环境系列:Apache2.4.37
一.安装 进入官网http://www.apache.org/,滑至最下方,排名第一的HTTP Server就是我们需要的. 当前时间的最新版本是2.4.37.呃……并没有msi版本,我们选择最后一个 ...
- C#比较两个由基本数据类型构成的object类型
/// <summary> /// 比较查询条件 /// </summary> public class ModelExtensions { /// <summary&g ...
- Linux 文件权限管理
1.文件权限的概述 在Linux系统下,使用权限来保护资源的安全将是一种不错的选择.系统中每个文件的权限都有可读(r).可写(w)和可执行(x)这三种权限,它们分别对应权限数值4.2 和1.系统为每个 ...
- php+qrcode类+生成二维码方法
//生成二维码 public function qrcode() { $data = input(); if(!$data['param']){ return json(['code ' => ...
- VMware Converter Standalone支持Unix系统吗?
支持的客户操作系统: Windows Vista SP2 (32-bit and 64-bit) Windows Server 2008 SP2 (32-bit and 64-bit) Windows ...
- Boosting Static Representation Robustness for Binary Clone Search against Code Obfuscation and Compiler Optimization
用于理解恶意软件的内部工作原理,并发现系统中的漏洞,逆向工程是一种耗费人工的却很重要的技术.汇编克隆搜索引擎是通过识别那些重复的或者已知的部件来帮助逆向工程师的工作,要想设计健壮的克隆搜索引擎是一项挑 ...
- 持续代码质量管理-SonarQube Scanner部署
1. SonarQube Scanner地址 上一篇文章我们安装了SonarQube-7.3,让我们可以在页面查看代码质量.但是具体的扫描工作则需要SonarQube Scanner完成. 下载页面 ...
- C语言简单实现链栈基本几个功能
接着上一次的顺序栈,今天我记一下链栈,因为我也是刚学不久,有些地方也稍稍理解不了,所以,一起共勉.我会用我自己结合教材上画的图,争取跟代码一起结合,用文字和图最大化的解释代码,这样的话 ...