Cet article présente en détail les étapes de mise en œuvre du plug-in glisser-déposer JS. Il analyse principalement en détail les six étapes suivantes :
1. Le principe du plug-in glisser-déposer js
2. L'effet le plus basique obtenu sur la base du principe
3. Abstraction et optimisation du code
4. Extension : éléments glisser-déposer efficaces
5. Optimisation des performances et résumé
6. plug-in jquery
Le glisser-déposer JS est un effet de page Web courant. Cet article implémentera un simple plug-in JS à partir de zéro.
1. Le principe du plug-in glisser-déposer js
Quelles sont les opérations courantes de glisser-déposer ? L'ensemble du processus comporte probablement les étapes suivantes :
1. Cliquez sur l'élément glissé avec la souris
2. Appuyez et maintenez la souris et déplacez la souris
3. Faites glisser l'élément vers une certaine position et relâchez la souris
Le processus ici implique trois événements DOM : onmousedown, onmousemove, onmouseup. Donc l'idée de base du glisser est :
1. Cliquez sur l'élément glissé avec la souris pour déclencher onmousedown
(1) Définissez la déplaçabilité de l'élément actuel sur true, indiquant qu'il peut être déplacé
(2) Enregistrez les coordonnées actuelles de la souris x, y
(3) Enregistrez les coordonnées x,y de l'élément actuel
2. Déplacez la souris pour déclencher onmousemove
(1) Déterminez si l'élément peut être glissé-déposé, si c'est le cas, passez à l'étape 2, sinon revenez directement à
(2) Si l'élément peut être déplacé, définissez les coordonnées de l'élément
La coordonnée x de l'élément = la distance horizontale déplacée par la souris. La coordonnée x d'origine de l'élément = la coordonnée x actuelle de la souris - la coordonnée x avant la souris. de l'élément
La coordonnée y de l'élément = la distance horizontale déplacée par la souris. La coordonnée y d'origine de l'élément = la coordonnée y actuelle de la souris - la coordonnée y avant la souris. La coordonnée y d'origine de l'élément
3. Relâchez la souris pour déclencher onmouseup
(1) Définissez l'état déplaçable de la souris sur falseRetour en haut
2. L'effet le plus basique obtenu sur la base du principe
Avant de réaliser l'effet de base, il y a quelques points qui doivent être expliqués :
1. Si un élément veut être déplacé, son attribut de position doit être relatif ou absolu
2. Obtenez les coordonnées de la souris via event.clientX et event.clientY
3. onmousemove est lié à l'élément document plutôt qu'à l'élément glisser lui-même, ce qui peut résoudre le problème de retard ou d'arrêt du mouvement causé par un glissement rapide
Le code est le suivant :
var dragObj = document.getElementById("test"); dragObj.style.left = "px"; dragObj.style.top = "px"; var mouseX, mouseY, objX, objY; var dragging = false; dragObj.onmousedown = function (event) { event = event || window.event; dragging = true; dragObj.style.position = "relative"; mouseX = event.clientX; mouseY = event.clientY; objX = parseInt(dragObj.style.left); objY = parseInt(dragObj.style.top); } document.onmousemove = function (event) { event = event || window.event; if (dragging) { dragObj.style.left = parseInt(event.clientX - mouseX + objX) + "px"; dragObj.style.top = parseInt(event.clientY - mouseY + objY) + "px"; } } document.onmouseup = function () { dragging = false; }
; (function (window, undefined) { var dom = { //绑定事件 on: function (node, eventName, handler) { if (node.addEventListener) { node.addEventListener(eventName, handler); } else { node.attachEvent("on" + eventName, handler); } }, //获取元素的样式 getStyle: function (node, styleName) { var realStyle = null; if (window.getComputedStyle) { realStyle = window.getComputedStyle(node, null)[styleName]; } else if (node.currentStyle) { realStyle = node.currentStyle[styleName]; } return realStyle; }, //获取设置元素的样式 setCss: function (node, css) { for (var key in css) { node.style[key] = css[key]; } } }; window.Drag = Drag; })(window, undefined);
function DragElement(node) { this.node = node;//被拖拽的元素节点 this.x = ;//拖拽之前的x坐标 this.y = ;//拖拽之前的y坐标 } DragElement.prototype = { constructor: DragElement, init: function () { this.setEleCss({ "left": dom.getStyle(node, "left"), "top": dom.getStyle(node, "top") }) .setXY(node.style.left, node.style.top); }, //设置当前的坐标 setXY: function (x, y) { this.x = parseInt(x) || ; this.y = parseInt(y) || ; return this; }, //设置元素节点的样式 setEleCss: function (css) { dom.setCss(this.node, css); return this; } }
function Mouse() { this.x = ; this.y = ; } Mouse.prototype.setXY = function (x, y) { this.x = parseInt(x); this.y = parseInt(y); }
Si une page peut contenir plusieurs éléments glisser-déposer, à quoi devez-vous faire attention :
1. Chaque élément correspond à une instance d'objet glisser2. Chaque page ne peut contenir qu'un seul élément glissé
A cet effet, nous définissons un objet unique pour enregistrer la configuration pertinente :
这个对象中有三个属性:
(1)zIndex:用来赋值给拖拽对象的zIndex属性,有多个拖拽对象时,当两个拖拽对象重叠时,会造成当前拖拽对象有可能被挡住,通过设置zIndex使其显示在最顶层
(2)draggingObj:用来保存正在拖拽的对象,在这里去掉了前面的用来判断是否可拖拽的变量,通过draggingObj来判断当前是否可以拖拽以及获取相应的拖拽对象
(3)mouse:唯一的鼠标对象,用来保存当前鼠标的坐标等信息
最后是绑定onmousedown,onmouseover,onmouseout事件,整合上面的代码如下:
; (function (window, undefined) { var dom = { //绑定事件 on: function (node, eventName, handler) { if (node.addEventListener) { node.addEventListener(eventName, handler); } else { node.attachEvent("on" + eventName, handler); } }, //获取元素的样式 getStyle: function (node, styleName) { var realStyle = null; if (window.getComputedStyle) { realStyle = window.getComputedStyle(node, null)[styleName]; } else if (node.currentStyle) { realStyle = node.currentStyle[styleName]; } return realStyle; }, //获取设置元素的样式 setCss: function (node, css) { for (var key in css) { node.style[key] = css[key]; } } }; //#region 拖拽元素类 function DragElement(node) { this.node = node; this.x = ; this.y = ; } DragElement.prototype = { constructor: DragElement, init: function () { this.setEleCss({ "left": dom.getStyle(node, "left"), "top": dom.getStyle(node, "top") }) .setXY(node.style.left, node.style.top); }, setXY: function (x, y) { this.x = parseInt(x) || ; this.y = parseInt(y) || ; return this; }, setEleCss: function (css) { dom.setCss(this.node, css); return this; } } //#endregion //#region 鼠标元素 function Mouse() { this.x = ; this.y = ; } Mouse.prototype.setXY = function (x, y) { this.x = parseInt(x); this.y = parseInt(y); } //#endregion //拖拽配置 var draggableConfig = { zIndex: , draggingObj: null, mouse: new Mouse() }; function Drag(ele) { this.ele = ele; function mouseDown(event) { var ele = event.target || event.srcElement; draggableConfig.mouse.setXY(event.clientX, event.clientY); draggableConfig.draggingObj = new DragElement(ele); draggableConfig.draggingObj .setXY(ele.style.left, ele.style.top) .setEleCss({ "zIndex": draggableConfig.zIndex++, "position": "relative" }); } ele.onselectstart = function () { //防止拖拽对象内的文字被选中 return false; } dom.on(ele, "mousedown", mouseDown); } dom.on(document, "mousemove", function (event) { if (draggableConfig.draggingObj) { var mouse = draggableConfig.mouse, draggingObj = draggableConfig.draggingObj; draggingObj.setEleCss({ "left": parseInt(event.clientX - mouse.x + draggingObj.x) + "px", "top": parseInt(event.clientY - mouse.y + draggingObj.y) + "px" }); } }) dom.on(document, "mouseup", function (event) { draggableConfig.draggingObj = null; }) window.Drag = Drag; })(window, undefined);
调用方法:Drag(document.getElementById("obj"));
注意的一点,为了防止选中拖拽元素中的文字,通过onselectstart事件处理程序return false来处理这个问题。
四、扩展:有效的拖拽元素
我们常见的一些拖拽效果很有可能是这样的:
弹框的顶部是可以进行拖拽操作的,内容区域是不可拖拽的,怎么实现这样的效果呢:
首先优化拖拽元素对象如下,增加一个目标元素target,表示被拖拽对象,在上图的登录框中,就是整个登录窗口。
被记录和设置坐标的拖拽元素就是这个目标元素,但是它并不是整个部分都是拖拽的有效部分。我们在html结构中为拖拽的有效区域添加类draggable表示有效拖拽区域:
然后修改Drag方法如下:
function drag(ele) { var dragNode = (ele.querySelector(".draggable") || ele); dom.on(dragNode, "mousedown", function (event) { var dragElement = draggableConfig.dragElement = new DragElement(ele); draggableConfig.mouse.setXY(event.clientX, event.clientY); draggableConfig.dragElement .setXY(dragElement.target.style.left, dragElement.target.style.top) .setTargetCss({ "zIndex": draggableConfig.zIndex++, "position": "relative" }); }).on(dragNode, "mouseover", function () { dom.setCss(this, draggableStyle.dragging); }).on(dragNode, "mouseout", function () { dom.setCss(this, draggableStyle.defaults); }); }
主要修改的是绑定mousedown的节点变成了包含draggable类的有效元素,如果不含有draggable,则整个元素都是有效元素。
五、性能优化和总结
由于onmousemove在一直调用,会造成一些性能问题,我们可以通过setTimout来延迟绑定onmousemove事件,改进move函数如下
function move(event) { if (draggableConfig.dragElement) { var mouse = draggableConfig.mouse, dragElement = draggableConfig.dragElement; dragElement.setTargetCss({ "left": parseInt(event.clientX - mouse.x + dragElement.x) + "px", "top": parseInt(event.clientY - mouse.y + dragElement.y) + "px" }); dom.off(document, "mousemove", move); setTimeout(function () { dom.on(document, "mousemove", move); }, ); } }
总结:
整个拖拽插件的实现其实很简单,主要是要注意几点
1、实现思路:元素拖拽位置的改变就等于鼠标改变的距离,关键在于获取鼠标的变动和元素原本的坐标
2、通过setTimeout来延迟加载onmousemove事件来提供性能
六、jquery插件化
简单地将其封装成jquery插件,主要是相关的dom方法替换成jquery方法来操作
; (function ($, window, undefined) { //#region 拖拽元素类 function DragElement(node) { this.target = node; node.onselectstart = function () { //防止拖拽对象内的文字被选中 return false; } } DragElement.prototype = { constructor: DragElement, setXY: function (x, y) { this.x = parseInt(x) || ; this.y = parseInt(y) || ; return this; }, setTargetCss: function (css) { $(this.target).css(css); return this; } } //#endregion //#region 鼠标元素 function Mouse() { this.x = ; this.y = ; } Mouse.prototype.setXY = function (x, y) { this.x = parseInt(x); this.y = parseInt(y); } //#endregion //拖拽配置 var draggableConfig = { zIndex: , dragElement: null, mouse: new Mouse() }; var draggableStyle = { dragging: { cursor: "move" }, defaults: { cursor: "default" } } var $document = $(document); function drag($ele) { var $dragNode = $ele.find(".draggable"); $dragNode = $dragNode.length > ? $dragNode : $ele; $dragNode.on({ "mousedown": function (event) { var dragElement = draggableConfig.dragElement = new DragElement($ele.get()); draggableConfig.mouse.setXY(event.clientX, event.clientY); draggableConfig.dragElement .setXY(dragElement.target.style.left, dragElement.target.style.top) .setTargetCss({ "zIndex": draggableConfig.zIndex++, "position": "relative" }); }, "mouseover": function () { $(this).css(draggableStyle.dragging); }, "mouseout": function () { $(this).css(draggableStyle.defaults); } }) } function move(event) { if (draggableConfig.dragElement) { var mouse = draggableConfig.mouse, dragElement = draggableConfig.dragElement; dragElement.setTargetCss({ "left": parseInt(event.clientX - mouse.x + dragElement.x) + "px", "top": parseInt(event.clientY - mouse.y + dragElement.y) + "px" }); $document.off("mousemove", move); setTimeout(function () { $document.on("mousemove", move); }, ); } } $document.on({ "mousemove": move, "mouseup": function () { draggableConfig.dragElement = null; } }); $.fn.drag = function (options) { drag(this); } })(jQuery, window, undefined)
以上就是本文对JS拖拽插件实现步骤的详细介绍,希望对大家有所帮助。