Home Web Front-end JS Tutorial In-depth study of javascript drag and drop effect

In-depth study of javascript drag and drop effect

Dec 14, 2016 pm 04:05 PM

The drag-and-drop effect, also called drag-and-drop, is one of the most common js special effects.
If you ignore many details, it is very simple to implement, but the details are often the difficulty.
The prototype of this program was created when I was doing image cutting effects. At that time, I referred to several similar effects and learned a lot from muxrwc and BlueDestiny.
Although I feel good every time I sort it out, every once in a while I will find that somewhere can be improved, there is an error somewhere, and certain needs need to be realized, just like the knowledge I have learned.

Considering that some people may only need simple drag and drop, there is a simplified version of drag and drop SimpleDrag to facilitate learning.

Program Principle

Here we take SimpleDrag as an example to explain the basic principles.

First, a drag-and-drop object is required in the initialization program:

this.Drag = $(drag);

There are also two parameters to record the coordinates of the mouse relative to the drag-and-drop object at the beginning:

this._x = this. _y = 0;

There are also two event object functions for adding and removing events:

this._fM = BindAsEventListener(this, this.Move);
this._fS = Bind(this, this.Stop);

They are dragging program and stop dragging program respectively.
The position of the drag-and-drop object must be absolute positioning:

this.Drag.style.position = "absolute";

Finally, bind the Start drag-and-drop program to the mousedown event of the drag-and-drop object:

addEventHandler(this. Drag, "mousedown", BindAsEventListener(this, this.Start));

When the mouse is pressed on the drag and drop object, the Start program will be triggered. It is mainly used to prepare for dragging. Here, the coordinates of the mouse relative to the drag and drop object are recorded. :

this._x = oEvent.clientX - this.Drag.offsetLeft;
this._y = oEvent.clientY - this.Drag.offsetTop;

And bind the _fM drag program and _fS stop drag program respectively Binding mousemove and mouseup events to document:

addEventHandler(document, "mousemove", this._fM);
addEventHandler(document, "mouseup", this._fS);

Binding to document can ensure that the event occurs throughout the window are valid in the document.

When the mouse moves on the document, the Move program will be triggered. Here is the program to implement dragging.
The left and top that should be set for the drag and drop object can be obtained by the difference between the current coordinate value of the mouse and the relative coordinate value of the mouse when dragging started:

this.Drag.style.left = oEvent.clientX - this._x + "px";
this.Drag.style.top = oEvent.clientY - this._y + "px";

After finally releasing the mouse, the Stop program is triggered to end the drag and drop.
The main function here is to remove the events added to the document in the Start program:

removeEventHandler(document, "mousemove", this._fM);
removeEventHandler(document, "mouseup", this._fS);

This way A simple drag-and-drop program is ready. Let’s talk about other extensions and details.

Drag and drop lock

There are three types of locks, namely: horizontal lock (LockX), vertical lock (LockY), and complete lock (Lock).
This is relatively simple. To lock the horizontal and vertical directions, you only need to judge whether it is locked in Move and then set left and top. If it is fully locked, just return directly.

if(!this.LockX){ this.Drag.style.left = ...; }
if(!this.LockY){ this.Drag.style.top = ...; }

Trigger object

The trigger object is used to trigger the drag-and-drop program. Sometimes the entire drag-and-drop object does not need to be used for triggering. In this case, the trigger object is needed.
After using the trigger object, the drag and drop object is still moved, but the trigger object is used to trigger the drag and drop (the general use is to put the trigger object into the drag and drop object).

Scope Limit

To set the range limit, you must first set Limit to true. There are two types of range restrictions, namely fixed range and container range restrictions, which are mainly set in the Move program.
The principle is that when the compared value exceeds the range, the values ​​to be set for left and top are corrected so that the drag and drop object can remain within the set range.

Fixed range limit

Container range limit is to specify the drag and drop range of the top, bottom, left, and right.
The meaning of each attribute is:

upper (mxTop): top limit;

lower (mxBottom): top+offsetHeight limit;

left (mxLeft): left limit;

right (mxRight): left+offsetWidth limit .

If the range is set incorrectly, it may cause the up and down or left and right to exceed the range at the same time. There is a Repair program in the program to correct the range parameters.
The Repair program will be executed in the program initialization and Start program. Correct mxRight and mxBottom in the Repair program:

this.mxRight = Math.max(this.mxRight, this.mxLeft + this.Drag.offsetWidth);
this. mxBottom = Math.max(this.mxBottom, this.mxTop + this.Drag.offsetHeight);

where mxLeft+offsetWidth and mxTop+offsetHeight are the minimum range values ​​of mxRight and mxBottom respectively.

Correct the movement parameters according to the range parameters:

iLeft = Math.max(Math.min(iLeft, mxRight - this.Drag.offsetWidth), mxLeft);
iTop = Math.max(Math.min(iTop, mxBottom - this.Drag.offsetHeight), mxTop);

Take a larger value for the upper left side and a smaller value for the lower right side.

容器范围限制

容器范围限制的意思就是把范围限制在一个容器_mxContainer内。 
要注意的是拖放对象必须包含在_mxContainer中,因为程序中是使用相对定位来设置容器范围限制的(如果是在容器外就要用绝对定位,这样处理就比较麻烦了),还有就是容器空间要比拖放对象大,这个就不用说明了吧。 
原理跟固定范围限制差不多,只是范围参数是根据容器的属性的设置的。

当设置了容器,会自动把position设为relative来相对定位:

!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative");

注意relative要在获取offsetLeft和offsetTop即设置_x和_y之前设置,offset才能正确获取值。

由于是相对定位,对于容器范围来说范围参数上下左右的值分别是0、clientHeight、0、clientWidth。

clientWidth和clientHeight是容器可视部分的宽度和高度(详细参考这里)。 
为了容器范围能兼容固定范围的参数,程序中会获取容器范围和固定范围中范围更小的值:

mxLeft = Math.max(mxLeft, 0); 
mxTop = Math.max(mxTop, 0); 
mxRight = Math.min(mxRight, this._mxContainer.clientWidth); 
mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight);

注意如果在程序执行之前设置过拖放对象的left和top而容器没有设置relative,在自动设置relative时会发生移位现象,所以程序在初始化时就执行一次Repair程序防止这种情况。因为offsetLeft和offsetTop要在设置relative之前获取才能正确获取值,所以在Start程序中Repair要在设置_x和_y之前执行。

因为设置相对定位的关系,容器_mxContainer设置过后一般不要取消或修改,否则很容易造成移位异常。

鼠标捕获

我在一个拖放实例中看到,即使鼠标移动到浏览器外面,拖放程序依然能够执行,仔细查看后发现是用了setCapture。 
鼠标捕获(setCapture)是这个程序的重点,作用是将鼠标事件捕获到当前文档的指定的对象。这个对象会为当前应用程序或整个系统接收所有鼠标事件。 
使用很简单:

this._Handle.setCapture();

setCapture捕获以下鼠标事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。 
程序中主要是要捕获onmousemove和onmouseup事件。 
msdn的介绍中还说到setCapture有一个bool参数,用来设置在容器内的鼠标事件是否都被容器捕获。
容器就是指调用setCapture的对象,大概意思就是: 
参数为true时(默认)容器会捕获容器内所有对象的鼠标事件,即容器内的对象不会触发鼠标事件(跟容器外的对象一样); 
参数为false时容器不会捕获容器内对象的鼠标事件,即容器内的对象可以正常地触发事件和取消冒泡。 
而对于容器外的鼠标事件无论参数是什么都会被捕获, 
可以用下面这个简单的例子测试一下(ie):

 
 

mouseover
 
<script>document.body.setCapture(); </script> 
 

这里的参数是true,一开始body会捕获所有鼠标事件,即使鼠标经过div也不会触发onmousemove事件。 
换成false的话,div就可以捕获鼠标事件,就能触发onmousemove事件了。

拖放结束后还要使用releaseCapture释放鼠标,这个可以放在Stop程序中:

this._Handle.releaseCapture();

setCapture是ie的鼠标捕获方法,对于ff也有对应的captureEvents和releaseEvents方法。 
但这两个方法只能由window来调用,而且muxrwc说这两个方法在DOM2里已经废弃了,在ff里已经没用了。 
不过ff里貌似会自动设置取消鼠标捕获,但具体的情形就不清楚了,找不到一个比较详细的介绍,谁有这方面的资料记得告诉我啊。

下面都是我的猜测,ff的鼠标捕获相当于能自动设置和释放的document.body.setCapture(false)。 
因为我测试下面的程序,发现ie和ff效果是差不多的: 
ie:

 
 

 
<script> <br>document.body.onmousedown=function(){this.setCapture(false)} <br>document.body.onmouseup=function(){this.releaseCapture()} <br>document.onmousemove=function(){aa.innerHTML+=1} <br></script> 
 

ff:

 
 


<script> <br>document.onmousemove=function(){aa.innerHTML+=1} <br></script>

Unfortunately, there is no authoritative information reference. Guess, there are still many things that I haven’t understood yet and I’ll study them later.

Note that there is a bug in mouse capture under ff2. When the drag-and-drop object has no text content inside and is dragged and dropped outside the browser, the capture will fail.
Insert an empty text into the drag and drop object, such as   This can be solved, but this bug has been fixed in ff3.

Focus lost

Under normal circumstances, mouse capture can capture events normally, but if the focus of the browser window is lost, the capture will fail.
I have temporarily tested that operations that can cause focus loss include switching windows (including alt+tab), alert and popup and other pop-up forms.
When the focus is lost, the Stop program should be executed at the same time to end the drag and drop. However, when the focus is lost, the mouseup event cannot be captured, that is, _fS cannot be triggered.
Fortunately, IE has an onlosecapture event that will be triggered when the capture fails. For this situation, you can set it like this:

addEventHandler(this._Handle, "losecapture", this._fS);

and remove it in the Stop program:

removeEventHandler(this._Handle, "losecapture", this._fS);

But ff does not have a similar method, but muxrwc finds a window.onblur event that replaces losecapture, then you can set it in the Start program:

addEventHandler(window, "blur", this._fS);

Remove in the Stop program:

removeEventHandler(window, "blur", this._fS);

That ie also has a window.onblur event, then use window.onblur instead of losecapture Wouldn't it save a piece of code?
Then I did some tests and found that basically any situation that triggers losecapture will trigger window.onblur at the same time, which seems to work.
So I modified the program to use window.onblur instead of losecapture, but something went wrong after testing. I found that if I used alt+tab to switch to another window, dragging could continue, but the focus should have been lost at this time.

So I eliminated the test and program code one by one, and found that if DTD is used, window.onblur will not be triggered until it gains focus again.
You can use the following code to test:


<script>window.onblur=function(){alert(1)} </script>

Window.onblur will only be triggered after switching to other programs and then switching back. There are a few more weird situations that I won’t mention. Anyway, using window.onblur in IE is not ideal.

Default action

Dragging and dropping the text content, connections and pictures in the selected state will trigger the system's default action. For example, dragging the mouse on a picture in IE will become a prohibited operation state, which will cause the drag and drop program to be executed. fail.

However, after setCapture is set in IE, drag-and-drop operations and content selection with the mouse through the user interface will be prohibited.
It means that after setCapture, you cannot drag and drop and select the document content. Note that drag and drop here refers to the default action of the system. For example, ondragstart will not be triggered.
However, if the parameter of setCapture is false, the object in the container can still trigger the event (see the mouse capture part for details), so the parameter of setCapture should be set to true or keep the default value.

The mouse capture of ff does not have this function, but it can be solved by using preventDefault to cancel the default action of the event:

oEvent.preventDefault();

ps: It is said that using preventDefault will cause mouseup loss, but I am in ff3 We haven't found any in the test. If you find any mouseup loss, please tell me.

Clear selection

ie. After setting setCapture, content selection will be prohibited, but therefore the content that has been selected before setting will not be cleared. And after setting, you can also select content through other methods,
For example, use ctrl+a to select content.
ps: onkeydown, onkeyup and onkeypress events will not be affected by mouse capture.
And ff can clear the original selected content when mousedown, but drag the mouse and ctrl+a will still continue to select the content.
However, after discarding the system default action, this choice will not affect the drag and drop operation. The setting here is mainly for a better experience.

In the past, I used the method of disabling the selection of drag and drop objects to achieve the goal, that is, setting the onselectstart of the drag and drop object in IE to return false, and setting the style MozUserSelect (css:-moz-user-select) to none in FF.
But this method can only prevent the drag-and-drop object itself from being selected. Later, I found a better way to clear the selection, which not only does not affect the selection effect of the drag-and-drop object, but also clears the entire document:

ie: document.selection .empty()

ff: window.getSelection().removeAllRanges()

In order to prevent content from being selected during the drag and drop process, put it into the Move program. The following is the compatible writing method:

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

margin

There is another situation. When the margin is set on the drag and drop object, it will be misaligned when dragging and dropping (you can test it by setting margin on the SimpleDrag drag and drop object).
The reason is that offset is used when setting _x and _y in the Start program, and this value includes margin, so this margin must be subtracted before setting left and top.
But if margin is removed in the Start program, there will be a calculation error when setting the range limit in the Move program,
So it is best to get the value in the Start program:

this._marginLeft = parseInt(CurrentStyle(this.Drag) .marginLeft) || 0;
this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0;

where CurrentStyle is used to obtain the final style. See the final style section here for details.

Set the value in the Move program:

this.Drag.style.left = iLeft - this._marginLeft + "px";
this.Drag.style.top = iTop - this._marginTop + "px";

It should be noted that the margin must be set after the range is corrected, otherwise it will be misaligned.

【Transparent background bug】

There is a transparent background bug in IE (I don’t know if it is a bug). You can use the following code to test it:






You will find that the background click triggers The event cannot be triggered, but it can still be triggered by clicking on the border.
Why? Then use the following code to test:






< /div>


< /body>

You should be able to get a rough idea. The following two divs cannot trigger events if they exceed the body (that is, exceed the red box).
That is to say, when the point that triggers the event is outside the body, and the background is transparent, then it will be mistakenly thought that the trigger point is in a blank place outside the body, so the event cannot be triggered.
The solution is to keep the event trigger point within the body, or set a non-transparent background.

The problem can be solved by just setting a background color for the drag and drop object in the program, but sometimes the requirement is to be transparent (such as cutting effect), so what should I do?
The first thing that comes to mind is to add a background color and set it to be completely transparent, but then even the borders and objects in the container are completely transparent, which is not good.
A solution I thought of is to add a layer inside the container, cover the entire container, and set the background color and complete transparency:

with(this._Handle.appendChild(document.createElement("div")).style){
width = height = "100%"; backgroundColor = "#fff"; filter = "alpha(opacity:0)";
}

When you find that this bug appears in the program, set the program optional parameter Transparent to true. Such a layer will be automatically inserted.
If you have a better method, please give me some advice.

That’s it for the time being, but there are iframes, scrolling, etc. that I haven’t considered yet. I’ll look into them later if necessary.

For more related articles, please pay attention to the PHP Chinese website (www.php.cn)!


Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to enable Super Drag and Drop mode in Microsoft Edge How to enable Super Drag and Drop mode in Microsoft Edge Mar 18, 2024 am 09:40 AM

Microsoft Edge's drag-and-drop feature allows you to easily open links or text on web pages, which is both practical and time-saving. To use this feature, just drag and drop the link or text anywhere on the page. This article will show you how to enable or disable Super Drag and Drop mode in Microsoft Edge. What is Super Drag and Drop mode in Microsoft Edge? Microsoft Edge has introduced a new feature called &quot;Super Drag and Drop&quot; that allows users to simply drag and drop links to quickly open them in a new tab. Just drag and drop the link anywhere in the Edge browser window. Edge will automatically load the link in a new tab. In addition, users can also

A deep dive into models, data, and frameworks: an exhaustive 54-page review of efficient large language models A deep dive into models, data, and frameworks: an exhaustive 54-page review of efficient large language models Jan 14, 2024 pm 07:48 PM

Large-scale language models (LLMs) have demonstrated compelling capabilities in many important tasks, including natural language understanding, language generation, and complex reasoning, and have had a profound impact on society. However, these outstanding capabilities require significant training resources (shown in the left image) and long inference times (shown in the right image). Therefore, researchers need to develop effective technical means to solve their efficiency problems. In addition, as can be seen from the right side of the figure, some efficient LLMs (LanguageModels) such as Mistral-7B have been successfully used in the design and deployment of LLMs. These efficient LLMs can significantly reduce inference memory while maintaining similar accuracy to LLaMA1-33B

How to implement an online speech recognition system using WebSocket and JavaScript How to implement an online speech recognition system using WebSocket and JavaScript Dec 17, 2023 pm 02:54 PM

How to use WebSocket and JavaScript to implement an online speech recognition system Introduction: With the continuous development of technology, speech recognition technology has become an important part of the field of artificial intelligence. The online speech recognition system based on WebSocket and JavaScript has the characteristics of low latency, real-time and cross-platform, and has become a widely used solution. This article will introduce how to use WebSocket and JavaScript to implement an online speech recognition system.

WebSocket and JavaScript: key technologies for implementing real-time monitoring systems WebSocket and JavaScript: key technologies for implementing real-time monitoring systems Dec 17, 2023 pm 05:30 PM

WebSocket and JavaScript: Key technologies for realizing real-time monitoring systems Introduction: With the rapid development of Internet technology, real-time monitoring systems have been widely used in various fields. One of the key technologies to achieve real-time monitoring is the combination of WebSocket and JavaScript. This article will introduce the application of WebSocket and JavaScript in real-time monitoring systems, give code examples, and explain their implementation principles in detail. 1. WebSocket technology

How to implement an online reservation system using WebSocket and JavaScript How to implement an online reservation system using WebSocket and JavaScript Dec 17, 2023 am 09:39 AM

How to use WebSocket and JavaScript to implement an online reservation system. In today's digital era, more and more businesses and services need to provide online reservation functions. It is crucial to implement an efficient and real-time online reservation system. This article will introduce how to use WebSocket and JavaScript to implement an online reservation system, and provide specific code examples. 1. What is WebSocket? WebSocket is a full-duplex method on a single TCP connection.

How to use JavaScript and WebSocket to implement a real-time online ordering system How to use JavaScript and WebSocket to implement a real-time online ordering system Dec 17, 2023 pm 12:09 PM

Introduction to how to use JavaScript and WebSocket to implement a real-time online ordering system: With the popularity of the Internet and the advancement of technology, more and more restaurants have begun to provide online ordering services. In order to implement a real-time online ordering system, we can use JavaScript and WebSocket technology. WebSocket is a full-duplex communication protocol based on the TCP protocol, which can realize real-time two-way communication between the client and the server. In the real-time online ordering system, when the user selects dishes and places an order

I2V-Adapter from the SD community: no configuration required, plug and play, perfectly compatible with Tusheng video plug-in I2V-Adapter from the SD community: no configuration required, plug and play, perfectly compatible with Tusheng video plug-in Jan 15, 2024 pm 07:48 PM

The image-to-video generation (I2V) task is a challenge in the field of computer vision that aims to convert static images into dynamic videos. The difficulty of this task is to extract and generate dynamic information in the temporal dimension from a single image while maintaining the authenticity and visual coherence of the image content. Existing I2V methods often require complex model architectures and large amounts of training data to achieve this goal. Recently, a new research result "I2V-Adapter: AGeneralImage-to-VideoAdapter for VideoDiffusionModels" led by Kuaishou was released. This research introduces an innovative image-to-video conversion method and proposes a lightweight adapter module, i.e.

JavaScript and WebSocket: Building an efficient real-time weather forecasting system JavaScript and WebSocket: Building an efficient real-time weather forecasting system Dec 17, 2023 pm 05:13 PM

JavaScript and WebSocket: Building an efficient real-time weather forecast system Introduction: Today, the accuracy of weather forecasts is of great significance to daily life and decision-making. As technology develops, we can provide more accurate and reliable weather forecasts by obtaining weather data in real time. In this article, we will learn how to use JavaScript and WebSocket technology to build an efficient real-time weather forecast system. This article will demonstrate the implementation process through specific code examples. We

See all articles