JavaScript drag and drop effect code_javascript skills
WBOY
Release: 2016-05-16 18:57:40
Original
990 people have browsed it
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 learned. Considering that some people may only need a simple drag and drop, there is a simplified version of SimpleDrag for easy learning. Effect Preview ps: If you turn on ad filtering under maxthon, it is likely to be filtered out (I don’t know if there is any way to avoid it). Program Description [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:
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:
Note that the event must be bound to the document to ensure that the event is valid in the entire window document. If it is only bound to the drag and drop object, it is easy to drag too quickly and get out of touch. When the mouse moves on the document, the Move program will be triggered. Here is the program to implement dragging. The left and top values 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 ); Such 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 determine 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, which is set through the Handle attribute in the 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). ps: Another usage of the trigger object is to drag and drop multiple drag and drop objects with one trigger object at the same time by setting the same Handle. 【Range Limitation】 To set a 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: Top (mxTop): top limit; Down (mxBottom): top offsetHeight limit; Left (mxLeft): left limit; Right (mxRight) :left offsetWidth limit. If the range setting is incorrect, 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. 【Container scope limitation】 Container scope limitation means to limit the scope to one container_mxContainer. It should be noted that the drag and drop object must be included in _mxContainer, because the program uses relative positioning to set the container range limit (if it is outside the container, absolute positioning must be used, which will be more troublesome). Also, the container space is larger than the drag-and-drop object, so there is no need to explain this. The principle is similar to the fixed range limit, except that the range parameters are set according to the attributes of the container. When a container is set, the Repair program will automatically set position to relative for relative positioning: !this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer .style.position = "relative"); ps: CurrentStyle is used to obtain the final style (see the final style section here for details). Note that if the left and top of the drag-and-drop object are set before the program is executed but the container is not set to relative, shifting will occur when relative is automatically set, so the program will execute a Repair program during initialization to prevent this situation. Because offsetLeft and offsetTop must be obtained before setting relative to obtain the value correctly, Repair must be executed before setting _x and _y in the Start program. Due to relative positioning, for the container scope, the upper, lower, left and right values of the range parameters are 0, clientHeight, 0, clientWidth respectively. clientWidth and clientHeight are the width and height of the visible part of the container (refer here for details). 为了容器范围能兼容固定范围的参数,程序中会获取容器范围和固定范围中范围更小的值: Code mxLeft = Math.max(mxLeft, 0); mxTop = Math.max(mxTop, 0); mxRight = Math.min(mxRight, this._mxContainer.clientWidth); mxBottom = Math.min(mxBottom, this._mxContainer.clientHeight); 因为设置相对定位的关系,容器_mxContainer设置过后一般不要取消或修改,否则很容易造成移位异常。 【鼠标捕获】 我在一个拖放实例中看到,即使鼠标移动到浏览器外面,拖放程序依然能够执行,仔细查看后发现是用了setCapture。 鼠标捕获(setCapture)是这个程序的重点,作用是将鼠标事件捕获到当前文档的指定的对象。这个对象会为当前应用程序或整个系统接收所有鼠标事件。 使用很简单: this._Handle.setCapture(); setCapture捕获以下鼠标事件:onmousedown、onmouseup、onmousemove、onclick、ondblclick、onmouseover和onmouseout。 程序中主要是要捕获onmousemove和onmouseup事件。 msdn的介绍中还说到setCapture有一个bool参数,用来设置在容器内的鼠标事件是否都被容器捕获。 容器就是指调用setCapture的对象,大概意思就是: 参数为true时(默认)容器会捕获容器内所有对象的鼠标事件,即容器内的对象不会触发鼠标事件(跟容器外的对象一样); 参数为false时容器不会捕获容器内对象的鼠标事件,即容器内的对象可以正常地触发事件和取消冒泡。 而对于容器外的鼠标事件无论参数是什么都会被捕获,可以用下面这个简单的例子测试一下(ie): Code
Unfortunately, without authoritative information reference, we can only guess. There are still many things that we still don’t understand and we will study them later. Note that there is a bug in mouse capture under ff2. When there is no text content inside the drag-and-drop object and it 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 the 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 move it in the Stop program Except: removeEventHandler(this._Handle, "losecapture", this._fS); But ff does not have a similar method, but muxrwc finds a window.onblur event that replaces losecapture, so it can be set 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, using window.onblur instead of losecapture can 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 use alt tab to switch to another window, dragging can continue, but the focus should have been lost by 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> After switching to other programs, switch back again It will trigger window.onblur, and there are a few weird situations that I won’t mention. Anyway, using window.onblur in IE is not ideal. [Cancel default action] Drag-and-drop operations on text content, connections, and images in the selected state will trigger the system's default action. For example, dragging the mouse on an image in IE will become a prohibited operation state, which will cause This drag and drop procedure failed to execute. 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 events (see the mouse capture section 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 didn't find it in the test in ff3. If you find any mouseup loss, be sure to tell me. 【Clear Selection】 ie content selection will be prohibited after setting setCapture, but it will not clear the content that has been selected before setting, and content can also be selected through other methods after setting, 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 canceling 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. 但这种方法只能禁止拖放对象本身被选择,后来找到个更好的方法清除选择,不但不影响拖放对象的选择效果,还能对整个文档进行清除: ie:document.selection.empty() ff:window.getSelection().removeAllRanges() 为了防止在拖放过程中选择内容,所以把它放到Move程序中,下面是兼容的写法: window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); 【margin】 还有一个情况,当拖放对象设置了margin,那么拖放的时候就会错位(给SimpleDrag的拖放对象设置margin就可以测试)。 原因是在Start程序设置_x和_y时是使用offset获取的,而这个值是包括margin的,所以在设置left和top之前要减去这个margin。 但如果在Start程序中就去掉margin那么在Move程序中设置范围限制时就会计算错误, 所以最好是在Start程序中获取值: this._marginLeft = parseInt(CurrentStyle(this.Drag).marginLeft) || 0; this._marginTop = parseInt(CurrentStyle(this.Drag).marginTop) || 0; 在Move程序中设置值: this.Drag.style.left = iLeft - this._marginLeft + "px"; this.Drag.style.top = iTop - this._marginTop + "px"; 要注意margin要在范围修正之后再设置,否则会错位。 【透明背景bug】 在ie有一个透明背景bug(不知算不算bug),可以用下面的代码测试: Code
Can be compared with ie7 As a result, it can be seen that although the height of the inner div is set to 100%, after the height of the outer div is modified, it is not filled for some reason. If this div is a dragging object and suddenly half of it cannot be dragged, that will definitely not work. Fortunately, BlueDestiny told me a solution. Set the overflow of the object to hidden, and the divs inside will be automatically filled again. BlueDestiny said "The reason for this problem is because of the rendering problem of IE6. Through certain CSS properties, the DOM can be changed and rendered again." This bug can also be solved with zoom. Anyway, it is to make the dom re-rendered. render. When you find that this bug appears in the program, set the program optional parameter Transparent to true and such a layer will be automatically inserted. Insert a little knowledge here. If you are careful, you will find that in the above test code, I set a background color for the html. You can remove this background color and you will find that the background color will be set to the entire page. Although the body has always been used to set the background color of the page, but now you will have a doubt, the body is the part of the red box, why set it? The background color can be applied to the entire page, and setting the background color for html will display "normally". The reason for this can be seen from the background section of the w3c standard of CSS21: For HTML documents, however, we recommend that authors specify the background for the BODY element rather than the HTML element. For HTML documents whose root HTML element has computed values of 'transparent' for 'background-color' and 'none' for 'background-image', user agents must instead use the computed value of those properties from that HTML element's first BODY element child when painting backgrounds for the canvas, and must not paint a background for that BODY element. Such backgrounds must also be anchored at the same point as they would be if they were painted only for the root element. This does not apply to XHTML documents. 我英It sucks, so just try to translate it: For HTML documents, we recommend that authors (this is to browser producers) use the background of the BODY element instead of the HTML element. If the 'background-color' of the root element of the HTML document (HTML element) is 'transparent' and the 'background-image' is 'none' (these two happen to be the default values), then the HTML element is taken when setting the background The attribute value of the first BODY child element, and the background of that element is no longer rendered. The last two sentences are hard to understand, but they are enough to explain the reason. 【iframe】 If there is an iframe embedded on the page, you should pay attention because there will be problems with mouse capture on the iframe. For example, if you quickly move and drop on an iframe within a drag-and-drop container, or drag the mouse to an iframe outside the container, anyway, the mouse is on the iframe (note that there are no other elements separating it), problems will occur: First of all, the capture is invalid. If the mouse is on the iframe, it cannot be dragged, but losecapture will not be triggered, let alone the blur of the window. This is the same in IE and FF; Secondly, in IE If you rub the iframe a few more times, it may cause IE to die (for unknown reasons). Here are a few methods I thought of: Hide the iframe of the page, which is relatively simple, but some important information in the iframe may also be hidden, or cause the page layout to be misaligned, resulting in a poor user experience; Cancel the drag and drop after moving the mouse to the iframe. It is not difficult, but the user experience is also not good; Each iframe is covered with a transparent layer, which is very troublesome. The position and size of each iframe must be calculated; Use a transparent layer to cover the entire page. It is recommended and relatively simple. This method is introduced below. The overlay I made to imitate the LightBox content display effect can be applied here. First, instantiate a transparent overlay: var ol = new OverLay({ Opacity: 0 }); Then Just add ol.Show() and ol.Close() in the onStart and onStop events to show and hide the overlay, so as long as drag and drop is not triggered in the iframe, there will be no problem. If there are other better methods, please advise. That’s it for the time being. I didn’t expect that a little drag and drop can bring so much knowledge. We haven’t considered scrolling and other things yet. We will study them later if necessary.
Instructions for use Only one parameter is required when instantiating, which is the drag and drop object: new SimpleDrag("idDrag"); has the following optional parameters and attributes: Attribute: Default value // Description Handle: "", // Set the trigger object (use drag and drop object if not set) Limit: false, // Whether to set range limit (when it is true, the following parameters are useful, Can be a negative number) mxLeft:0,//Left limit mxRight:9999,//Right limit mxTop:0,//Top limit mxBottom:9999,//Bottom limit mxContainer:"",//Specify the limit within the container LockX:false,//Whether to lock horizontal drag and drop LockY:false,//Whether to lock vertical drag and drop Lock:false, //Whether to lock Transparent: false, //Whether to be transparent onStart:function(){},//Execute when starting to move onMove:function(){},//Execute when moving onStop:function(){}//Executed when the movement ends The attribute Drag is a drag and drop object. Transparent, Handle and mxContainer cannot be set after initialization.
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