Question
When I was doing business development recently, I encountered a requirement. When the user opened the pop-up window to fill in the content, he wanted to refer to the content in the blank background of the pop-up window, but the pop-up window blocked his sight, so the user wondered whether he could drag the pop-up window arbitrarily.
In fact, there is more than this scenario. In many form editors, report designers, online ps, and H5 editors, drag is one of the most basic functions.
Next, we will bring a simple experiment and make a simple version of the pop-up window drag and drop function.
Analysis
As you may have thought, there are only two core methods:
- Use
mousedown
,mousemove
,mouseup
to monitor drag events - Dynamically change the
left
andtop
positions of the pop-up window according to the current mouse position when dragging
Just add some detailed experience processing.
Code
1. Constructing the DOM
- Create a container that occupies a manipulable area
- Create a pop-up window inside the container to customize the content of the pop-up window
- At the last position in the pop-up window, place four borders for mounting drag events and monitoring mouse movement
- Finally, place a pop-up window mask layer to cover the content of the pop-up window when dragging, to prevent the mouse from moving too fast during dragging and triggering events in the pop-up window, such as input and selection events.
<!--Outer container-->
<div class="container">
<!--Internal pop-up window-->
<div class="dialog">
<!--The content of the pop-up window-->
Pop-up content
<!--Border-->
<div class="drag-bar-left"></div>
<div class="drag-bar-right"></div>
<div class="drag-bar-top"></div>
<div class="drag-bar-bottom"></div>
<!--Pop-up window mask-->
<div class="mask-drag"></div>
</div>
</div>
2. Adjust the style
- The width and height of the outer container are set to 100%, which can fill its outer parent element. Pay special attention to the use of relative positioning, so that the internal pop-up positioning can take effect
- The pop-up window needs to use absolute positioning to specify the position. You cannot use a percentage, because you need to change the position of the pop-up window in real time when dragging. At that time, the designated position is used
- The width of the four inner borders is set to 10px, and they are also fixed to the periphery of the pop-up window with absolute positioning
- The mask layer is hidden first, and then the pop-up window will be blocked when dragging
.container{
width:100%;
height:100%;
position:relative;
}
.dialog{
width:100px;
height:100px;
position:absolute;
left:50px;
top:50px;
background:gray;
}
.drag-bar-left{
background:transparent;
position: absolute;
left:0;
top:0;
bottom:0;
width:10px;
cursor: move;
display: block;
}
.drag-bar-right{
background:transparent;
position: absolute;
right:0;
top:0;
bottom:0;
width:10px;
cursor: move;
display: block;
}
.drag-bar-top{
background:transparent;
position: absolute;
left:0;
top:0;
right:0;
height:10px;
cursor: move;
display: block;
}
.drag-bar-bottom{
background:transparent;
position: absolute;
left:0;
right:0;
bottom:0;
height:10px;
cursor: move;
display: block;
}
/* When dragging, covering the entire bullet box and placing the mouse to trigger the buttons inside */
.mask-drag{
position: absolute;
cursor: move;
user-select: none;
left:0;
top:0;
}
3. Monitoring events
- Monitor the
mousedown/mousemove/mouseup
events of the four borders - Store the distance between the mouse position and the left frame of the pop-up window during
mousedown
diffX = e.clientX-drag.offsetLeft
(the same for the upper frame) - In the case of
mousemove
, subtract the distance from the mouse to the left frame according to the mouse position, and the position of the left frame of the pop-up window can be calculated in real time.left = e.clientX-diffX
- Use a mask layer to enhance the experience
- Handling browser compatibility
// carried out
initDragDialog();
/*
* DOM selector
* @param selector {String} css selector for element
* @param context {Element} root element
* usage: $$('head')
* result: You will get <head> element
*/
function $$(selector, context) {
context = context || document
const elements = context.querySelectorAll(selector)
return elements.length == 1
? Array.prototype.slice.call(elements)[0]
: Array.prototype.slice.call(elements)
}
/**
* The pop-up window supports dragging
*/
function initDragDialog(){
// Drag and drop function (mainly to trigger three events: onmousedown\onmousemove\onmouseup)
const drag = $$('.dialog');
const divMask = $$('.mask-drag');
const dragBarTop = $$('.drag-bar-top')
const dragBarBottom = $$('.drag-bar-bottom')
const dragBarLeft = $$('.drag-bar-left')
const dragBarRight = $$('.drag-bar-right')
dragBarTop.addEventListener('mousedown',mouseDownLisenter)
dragBarBottom.addEventListener('mousedown',mouseDownLisenter)
dragBarLeft.addEventListener('mousedown',mouseDownLisenter)
dragBarRight.addEventListener('mousedown',mouseDownLisenter)
// When you click on an object, you can use the drag object. Move and up are the global area, that is, the entire document is common. The document object should be used instead of the drag object (otherwise, when the drag object is used, the object can only move to the right or down )
function mouseDownLisenter (e) {
e = e || window.event // Compatible with IE browser
const diffX = e.clientX-drag.offsetLeft // The distance from the moment the mouse clicks on the object relative to the left border of the object = the distance of the position when clicked relative to the leftmost left of the browser-the distance of the left border of the object relative to the leftmost left of the browser
const diffY = e.clientY-drag.offsetTop
/* Low version ie bug: When an object is dragged out of the browser’s visual window, a scroll bar will appear,
The solution is to use two unique methods setCapture()\releaseCapture() in IE browser, these two methods,
You can let the mouse slide outside the browser to capture the event, and our bug is when the mouse moves out of the browser,
The function that the limit is exceeded becomes invalid. In this way, this problem can be solved. Note: These two methods are used in onmousedown and onmouseup */
if (typeof drag.setCapture !=='undefined') {
drag.setCapture()
}
// Cover the pop-up window
divMask.style.width = '100%';
divMask.style.height = '100%';
// Prevent the selected event from being triggered when the dragging speed is too fast
document.body.style.userSelect ='none'
document.onmousemove = function (e) {
e = e || window.event // Compatible with IE browser
let left = e.clientX-diffX
let top = e.clientY-diffY
// Control the range of dragged objects can only be in the browser window, and scroll bars are not allowed
if (left <0) {
left = 0
} else if (left> window.innerWidth-drag.offsetWidth) {
left = window.innerWidth-drag.offsetWidth
}
if (top <0) {
top = 0
} else if (top> window.innerHeight-drag.offsetHeight) {
top = window.innerHeight-drag.offsetHeight
}
// Regain the distance of the object when moving, and solve the phenomenon of shaking when dragging
drag.style.left = left +'px'
drag.style.top = top +'px'
drag.style.transform =''
}
document.onmouseup = function (e) {// no longer move when the mouse pops up
this.onmousemove = null
this.onmouseup = null // Prevent the mouse from looping after it pops up (that is, prevent the mouse from moving when it is put on)
// Fix low version ie bug
if (typeof drag.releaseCapture !=='undefined') {
drag.releaseCapture()
}
// Restore the hidden mask layer
divMask.style.width = '0';
divMask.style.height = '0';
document.body.style.userSelect =''
}
}
}
Demo
See the Pen drag by openHacking (@openhacking) on CodePen.
Summary
Basically, the demand for pop-up dragging is realized, and the native js writing method can be quickly used in any front-end framework such as vue/react/angular. This case is relatively concise and can be expanded to suit business functions according to one's own needs.
And when we write a function, we have to learn advanced thinking, such as
- How to change the size of the pop-up window?
- How to support drag and drop on the mobile terminal?
- Can it be extracted as a general tool function?
Time is limited, so when I have time ,I will update my learning experience later.
评论
发表评论