1. Preface
The purpose of mouse dragging elements is to drag many small dots on a page for fixed positioning, and then copy HTML and paste it in the development code of the page. This is a function that has been implemented many times. Without doing it well, I had to use the jQuery.fn.draggable plug-in. After getting in touch with some information and other people's ideas, I finally improved the drag function today. Let's take a look at its implementation.
2. Design ideas
Bind the mouse button on the drag element, bind the mouse to move in the document object, and the mouse bounces the event;
Why not bind all three events to the drag element? This is because when the mouse moves too fast, the mouse moves and pop-up event handlers will not execute
The code copy is as follows:
$target.bind('mousedown', fn);
$(document)
.bind('mousemove', fn)
.bind('mouseup', fn);
3. Source code implementation details
There are many things to note in implementing the source code:
1. First, in the mouse press event, when clicking and dragging the element, the area text may be selected. This is not what we need. The solution is as follows:
The code copy is as follows:
// Prevent regional text from being selected for chrome firefox ie9
e.preventDefault();
// for firefox ie9 || less than ie9
window.getSelection ? window.getSelection().removeAllRanges(): document.selection.empty();
2. If the drag element is an image (img tag), the mouse drags the image for a short distance, a prohibited prompt will appear, that is, the image cannot be dragged,
This is the default behavior of the browser, so just block the default behavior of the browser.
The code copy is as follows:
e.preventDefault();
3. Questions about boundaries (handling drag range)
The code implemented at the beginning is as follows:
The code copy is as follows:
// x,y represents the left and top value to be set by the drag element, limitObj is the drag area range object, and a problem was found during testing.
// During the dragging process, sometimes dragging objects cannot be directly close to the boundary
if ( x >= limitObj._left && x <= limitObj._right ) {
$target.css({ left: x + 'px' });
}
if ( y >= limitObj._top && y <= limitObj._bottom ) {
$target.css({ top: y + 'px' });
}
Think further: Why the above problem occurs? The reason is that the variable x may be less than limitObj._left or greater than limitObj._right. The same is true for variable y.
Therefore, the code needs to be processed like this:
The code copy is as follows:
if (x < limitObj._left) {
x = limitObj._left;
}
if (x > limitObj._right) {
x = limitObj._right;
}
if (y < limitObj._top) {
y = limitObj._top;
}
if (y > limitObj._bottom) {
y = limitObj._bottom;
}
$target.css({ left: x + 'px', top: y + 'px' });
Finally solved this problem, but cloudgamer gave a better way to write it:
The code copy is as follows:
$target.css({
left: Math.max( Math.min(x, limitObj._right), limitObj._left) + 'px',
top: Math.max( Math.min(y, limitObj._bottom), limitObj._top) + 'px'
});
Complete program source code:
The code copy is as follows:
$.fn.extend({
/**
* Auto: Blog Yuan Huazi yjh 2014/02/21
*/
drag: function(options) {
var dragStart, dragMove, dragEnd,
$boundaryElem, limitObj;
function _initOptions() {
var noop = function(){}, defaultOptions;
defaultOptions = { // Default configuration item
boundaryElem: 'body' // Boundary container
};
options = $.extend( defaultOptions, options || {} );
$boundaryElem = $(options.boundaryElem);
dragStart = options.dragStart || noop,
dragMove = options.dragMove || noop,
dragEnd = options.dragEnd || noop;
}
function _drag(e) {
var clientX, clientY, offsetLeft, offsetTop,
$target = $(this), self = this;
limitObj = {
_left: 0,
_top: 0,
_right: ($boundaryElem.innerWidth() || $(window).width()) - $target.outerWidth(),
_bottom: ($boundaryElem.innerHeight() || $(window).height()) - $target.outerHeight()
};
// Record the position when the mouse is pressed and the relative position of the drag element
clientX = e.clientX;
clientY = e.clientY;
offsetLeft = this.offsetLeft;
offsetTop = this.offsetTop;
dragStart.apply(this, arguments);
$(document).bind('mousemove', moveHandle)
.bind('mouseup', upHandle);
// Mouse movement event handling
function moveHandle(e) {
var x = e.clientX - clientX + offsetLeft;
var y = e.clientY - clientY + offsetTop;
$target.css({
left: Math.max( Math.min(x, limitObj._right), limitObj._left) + 'px',
top: Math.max( Math.min(y, limitObj._bottom), limitObj._top) + 'px'
});
dragMove.apply(self, arguments);
// Block the default behavior of the browser (the mouse drags the image for a short distance, a prohibited prompt will appear, that is, the image cannot be dragged anymore)
e.preventDefault();
}
// Mouse bounce event handling
function upHandle(e) {
$(document).unbind('mousemove', moveHandle);
dragEnd.apply(self, arguments);
}
}
_initOptions(); // Initialize the configuration object
$(this)
.css({ position: 'absolute' })
.each(function(){
$(this).bind('mousedown', function(e){
_drag.apply(this, [e]);
// Prevent regional text from being selected for chrome firefox ie9
e.preventDefault();
// for firefox ie9 || less than ie9
window.getSelection ? window.getSelection().removeAllRanges(): document.selection.empty();
});
});
return this;
}
});
Instance call:
The code copy is as follows:
// Call the instance
(function(){
$('.drag-elem').drag({
boundaryElem: '#boundary',
dragStart: function(){
$(this).html('<span>Prepare to drag</span>').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });
},
dragMove: function(){
var pos = $(this).position();
$(this).html('<span>Drag(' + pos.left + ',' + pos.top + ')</span>' );
},
dragEnd : function(){
$(this).html('<span>Drag end</span>');
}
});
}());