Maison interface Web js tutoriel javascript拖放效果深入研究

javascript拖放效果深入研究

Dec 14, 2016 pm 04:05 PM

拖放效果,也叫拖拽,学名Drag-and-drop ,是最常见的js特效之一。
如果忽略很多细节,实现起来很简单,但往往细节才是难点所在。
这个程序的原型是在做图片切割效果的时候做出来的,那时参考了好几个同类的效果,跟muxrwc和BlueDestiny学习了不少东西。
虽然每次整理都觉得很好了,不过每隔一段时间又会发现得某个地方可以改善,某个地方有错误,某些需求需要实现,就像自己学习的知识那样。

这里考虑到有的人可能只需要简单的拖放,所以有一个 简化版的拖放SimpleDrag ,方便学习。

程序原理

这里以SimpleDrag为例说一下基本原理。

首先初始化程序中要一个拖放对象:

this.Drag = $(drag);

还要两个参数在开始时记录鼠标相对拖放对象的坐标:

this._x = this._y = 0;

还有两个事件对象函数用于添加移除事件:

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

分别是拖动程序和停止拖动程序。 
拖放对象的position必须是absolute绝对定位:

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

最后把Start开始拖放程序绑定到拖放对象mousedown事件:

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

鼠标在拖放对象按住,就会触发Start程序,主要是用来准备拖动,在这里记录鼠标相对拖放对象的坐标:

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

并把_fM拖动程序和_fS停止拖动程序分别绑定到document的mousemove和mouseup事件:

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

绑定到document可以保证事件在整个窗口文档中都有效。

当鼠标在文档上移动时,就会触发Move程序了,这里就是实现拖动的程序。 
通过现在鼠标的坐标值跟开始拖动时鼠标相对的坐标值的差就可以得到拖放对象应该设置的left和top了:

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

最后放开鼠标后就触发Stop程序结束拖放。 
这里的主要作用是把Start程序中给document添加的事件移除:

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

这样一个简单的拖放程序就做好了,下面说说其他扩展和细节部分。

拖放锁定

锁定分三种,分别是:水平方向锁定(LockX)、垂直方向锁定(LockY)、完全锁定(Lock)。 
这个比较简单,水平和垂直方向的锁定只要在Move判断是否锁定再设置left和top就行,如果是完全锁定就直接返回。

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

触发对象

触发对象是用来触发拖放程序的。有的时候不需要整个拖放对象都用来触发,这时就需要触发对象了。 
使用了触发对象后,进行移动的还是拖放对象,只是用触发对象来触发拖放(一般的使用是把触发对象放到拖放对象里面)。

范围限制

要设置范围限制必须先把Limit设为true。范围限制分两种,分别是固定范围和容器范围限制,主要在Move程序中设置。 
原理是当比较的值超过范围时,修正left和top要设置的值使拖放对象能保持在设置的范围内。

固定范围限制

容器范围限制就是指定上下左右的拖放范围。 
各个属性的意思是:

上(mxTop):top限制;

下(mxBottom):top+offsetHeight限制;

左(mxLeft):left限制;

右(mxRight):left+offsetWidth限制。

如果范围设置不正确,可能导致上下或左右同时超过范围的情况,程序中有一个Repair程序用来修正范围参数的。
Repair程序会在程序初始化和Start程序中执行,在Repair程序中修正mxRight和mxBottom:

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

其中mxLeft+offsetWidth和mxTop+offsetHeight分别是mxRight和mxBottom的最小范围值。

根据范围参数修正移动参数:

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

对于左边上边要取更大的值,对于右边下面就要取更小的值。

容器范围限制

容器范围限制的意思就是把范围限制在一个容器_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> 
 

可惜没有权威的资料参考就只能猜猜了,还有很多还没有理解的地方以后再研究拉。

注意ff2下的鼠标捕获有一个bug,当拖放对象内部没有文本内容并拖放到浏览器外时捕获就会失效。 
给拖放对象插入一个空文本,例如 就可以解决,不过这个bug在ff3已经修正了。

焦点丢失

一般情况下,鼠标捕获都能正常捕获事件,但如果浏览器窗口的焦点丢失就会导致捕获失效。 
我暂时测试到会导致焦点丢失的操作包括切换窗口(包括alt+tab),alert和popup等弹出窗体。 
当焦点丢失时应该同时执行Stop程序结束拖放,但当焦点丢失就不能捕获mouseup事件也就是不能触发_fS。 
还好ie有onlosecapture事件会在捕获失效时触发,针对这个情况可以这样设置:

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

并在Stop程序中移除:

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

但ff没有类似的方法,不过muxrwc找到一个替代losecapture的window.onblur事件,那么可以在Start程序中设置:

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

在Stop程序中移除:

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

那ie也有window.onblur事件,那用window.onblur代替losecapture不就可以省一段代码了吗。 
接着我做了一些测试,发现基本上触发losecapture的情况都会同时触发window.onblur,看来真的可以。 
于是我修改程序用window.onblur代替losecapture,但测试后就出问题了,我发现如果我用alt+tab切换到另一个窗口,拖动还可以继续,但这个时候应该是已经丢失焦点了。

于是我逐一排除测试和程序代码,结果发现如果使用了DTD,那么window.onblur会在再次获得焦点时才会触发。 
大家可以用下面这段代码测试:

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

在切换到其他程序后,再切换回来才会触发window.onblur,还有几个比较怪异的状况就不说了,反正ie用window.onblur是不理想的了。

默认动作

对选择状态的文本内容、连接和图片等进行拖放操作会触发系统的默认动作,例如ie中拖动图片鼠标会变成禁止操作状态,这样会导致这个拖放程序执行失败。

不过ie在设置了setCapture之后,通过用户界面用鼠标进行拖放操作和内容选择都会被禁止。 
意思就是setCapture之后就不能对文档内容进行拖放和选择,注意这里的拖放是指系统的默认动作,例如ondragstart就不会被触发。 
不过如果setCapture的参数是false的话,容器内的对象还是可以触发事件的(具体看鼠标捕获部分),所以setCapture的参数要设成true或保留默认值。

而ff的鼠标捕获没有这个功能,但可以用preventDefault来取消事件的默认动作来解决:

oEvent.preventDefault();

ps:据说使用preventDefault会出现mouseup丢失的情况,但我在ff3中测试没有发现,如果各位发现任何mouseup丢失的情况,务必告诉我啊

清除选择

ie在设置setCapture之后内容选择都会被禁止,但也因此不会清除在设置之前就已经选择的内容,而且设置之后也能通过其他方式选择内容, 
例如用ctrl+a来选择内容。 
ps:onkeydown、onkeyup和onkeypress事件不会受到鼠标捕获影响。 
而ff在mousedown时就能清除原来选择的内容,但拖动鼠标,ctrl+a时还是会继续选择内容。 
不过在丢弃了系统默认动作之后,这样的选择并不会对拖放操作造成影响,这里设置主要还是为了更好的体验。

以前我用禁止拖放对象被选择的方法来达到目的,即ie中设置拖放对象的onselectstart返回false,在ff中设置样式MozUserSelect(css:-moz-user-select)为none。 
但这种方法只能禁止拖放对象本身被选择,后来找到个更好的方法清除选择,不但不影响拖放对象的选择效果,还能对整个文档进行清除:

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;

其中CurrentStyle是用来获取最终样式,详细看这里的最终样式部分。

在Move程序中设置值:

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

要注意margin要在范围修正只后再设置,否则会错位。

【透明背景bug】

在ie有一个透明背景bug(不知算不算bug),可以用下面的代码测试:

 
 
 

 
 

会发现背景点击触发不了事件,不过点击边框的话还是可以触发。 
为什么呢?再用下面的代码测试:

 
 
 
 

 
 
 
 
 

应该能看出个大概了,下面两个div超出body(即超出红色框)的部分就触发不了事件。 
也就是说当触发事件的点,在body以外,而背景又是透明的,那么就会误认为触发点是在了body外空白的地方,所以触发不了事件。 
那解决的方法就是,使事件触发点保持在body内,或者设置一个非透明背景。

那程序中只要给拖放对象设一个背景色就可以解决了,但有时需求正好是要透明(例如切割效果),那怎么办呢? 
首先想到的是加上背景色后设置完全透明,但这样连边框,容器内的对象等都完全透明了,这个不好。 
我想到的一个解决方法是在容器里面加一个层,覆盖整个容器,并设置背景色和完全透明:

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

当发现程序有这个bug出现,把程序可选参数Transparent设为true就会自动插入这样一个层了。
各位如果有更好的方法请多多指点。

暂时就研究到这里,不过还有iframe,滚屏等这些还没考虑到,等以后有需要了再来研究拉。

 更多相关文章请关注PHP中文网(www.php.cn)!


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment activer le mode Super Drag and Drop dans Microsoft Edge Comment activer le mode Super Drag and Drop dans Microsoft Edge Mar 18, 2024 am 09:40 AM

La fonctionnalité glisser-déposer de Microsoft Edge vous permet d'ouvrir facilement des liens ou du texte sur des pages Web, ce qui est à la fois pratique et rapide. Pour utiliser cette fonctionnalité, faites simplement glisser et déposez le lien ou le texte n'importe où sur la page. Cet article vous montrera comment activer ou désactiver le mode Super Drag and Drop dans Microsoft Edge. Qu’est-ce que le mode Super Glisser-Déposer dans Microsoft Edge ? Microsoft Edge a introduit une nouvelle fonctionnalité appelée « Super Drag and Drop » qui permet aux utilisateurs de simplement glisser-déposer des liens pour les ouvrir rapidement dans un nouvel onglet. Faites simplement glisser et déposez le lien n’importe où dans la fenêtre du navigateur Edge. Edge chargera automatiquement le lien dans un nouvel onglet. De plus, les utilisateurs peuvent également

Une plongée approfondie dans les modèles, les données et les frameworks : une revue exhaustive de 54 pages de grands modèles de langage efficaces Une plongée approfondie dans les modèles, les données et les frameworks : une revue exhaustive de 54 pages de grands modèles de langage efficaces Jan 14, 2024 pm 07:48 PM

Les modèles linguistiques à grande échelle (LLM) ont démontré des capacités convaincantes dans de nombreuses tâches importantes, notamment la compréhension du langage naturel, la génération de langages et le raisonnement complexe, et ont eu un impact profond sur la société. Cependant, ces capacités exceptionnelles nécessitent des ressources de formation importantes (illustrées dans l’image de gauche) et de longs temps d’inférence (illustrés dans l’image de droite). Les chercheurs doivent donc développer des moyens techniques efficaces pour résoudre leurs problèmes d’efficacité. De plus, comme on peut le voir sur le côté droit de la figure, certains LLM (LanguageModels) efficaces tels que Mistral-7B ont été utilisés avec succès dans la conception et le déploiement de LLM. Ces LLM efficaces peuvent réduire considérablement la mémoire d'inférence tout en conservant une précision similaire à celle du LLaMA1-33B

Comment mettre en œuvre un système de reconnaissance vocale en ligne à l'aide de WebSocket et JavaScript Comment mettre en œuvre un système de reconnaissance vocale en ligne à l'aide de WebSocket et JavaScript Dec 17, 2023 pm 02:54 PM

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de reconnaissance vocale en ligne Introduction : Avec le développement continu de la technologie, la technologie de reconnaissance vocale est devenue une partie importante du domaine de l'intelligence artificielle. Le système de reconnaissance vocale en ligne basé sur WebSocket et JavaScript présente les caractéristiques d'une faible latence, d'un temps réel et d'une multiplateforme, et est devenu une solution largement utilisée. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de reconnaissance vocale en ligne.

WebSocket et JavaScript : technologies clés pour mettre en œuvre des systèmes de surveillance en temps réel WebSocket et JavaScript : technologies clés pour mettre en œuvre des systèmes de surveillance en temps réel Dec 17, 2023 pm 05:30 PM

WebSocket et JavaScript : technologies clés pour réaliser des systèmes de surveillance en temps réel Introduction : Avec le développement rapide de la technologie Internet, les systèmes de surveillance en temps réel ont été largement utilisés dans divers domaines. L'une des technologies clés pour réaliser une surveillance en temps réel est la combinaison de WebSocket et de JavaScript. Cet article présentera l'application de WebSocket et JavaScript dans les systèmes de surveillance en temps réel, donnera des exemples de code et expliquera leurs principes de mise en œuvre en détail. 1. Technologie WebSocket

Comment mettre en œuvre un système de réservation en ligne à l'aide de WebSocket et JavaScript Comment mettre en œuvre un système de réservation en ligne à l'aide de WebSocket et JavaScript Dec 17, 2023 am 09:39 AM

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de réservation en ligne. À l'ère numérique d'aujourd'hui, de plus en plus d'entreprises et de services doivent fournir des fonctions de réservation en ligne. Il est crucial de mettre en place un système de réservation en ligne efficace et en temps réel. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de réservation en ligne et fournit des exemples de code spécifiques. 1. Qu'est-ce que WebSocket ? WebSocket est une méthode full-duplex sur une seule connexion TCP.

Comment utiliser JavaScript et WebSocket pour mettre en œuvre un système de commande en ligne en temps réel Comment utiliser JavaScript et WebSocket pour mettre en œuvre un système de commande en ligne en temps réel Dec 17, 2023 pm 12:09 PM

Introduction à l'utilisation de JavaScript et de WebSocket pour mettre en œuvre un système de commande en ligne en temps réel : avec la popularité d'Internet et les progrès de la technologie, de plus en plus de restaurants ont commencé à proposer des services de commande en ligne. Afin de mettre en œuvre un système de commande en ligne en temps réel, nous pouvons utiliser les technologies JavaScript et WebSocket. WebSocket est un protocole de communication full-duplex basé sur le protocole TCP, qui peut réaliser une communication bidirectionnelle en temps réel entre le client et le serveur. Dans le système de commande en ligne en temps réel, lorsque l'utilisateur sélectionne des plats et passe une commande

Adaptateur I2V de la communauté SD : aucune configuration requise, plug and play, parfaitement compatible avec le plug-in vidéo Tusheng Adaptateur I2V de la communauté SD : aucune configuration requise, plug and play, parfaitement compatible avec le plug-in vidéo Tusheng Jan 15, 2024 pm 07:48 PM

La tâche de génération d'image en vidéo (I2V) est un défi dans le domaine de la vision par ordinateur qui vise à convertir des images statiques en vidéos dynamiques. La difficulté de cette tâche est d'extraire et de générer des informations dynamiques dans la dimension temporelle à partir d'une seule image tout en conservant l'authenticité et la cohérence visuelle du contenu de l'image. Les méthodes I2V existantes nécessitent souvent des architectures de modèles complexes et de grandes quantités de données de formation pour atteindre cet objectif. Récemment, un nouveau résultat de recherche « I2V-Adapter : AGeneralImage-to-VideoAdapter for VideoDiffusionModels » dirigé par Kuaishou a été publié. Cette recherche introduit une méthode innovante de conversion image-vidéo et propose un module adaptateur léger, c'est-à-dire

JavaScript et WebSocket : créer un système efficace de prévisions météorologiques en temps réel JavaScript et WebSocket : créer un système efficace de prévisions météorologiques en temps réel Dec 17, 2023 pm 05:13 PM

JavaScript et WebSocket : Construire un système efficace de prévisions météorologiques en temps réel Introduction : Aujourd'hui, la précision des prévisions météorologiques revêt une grande importance pour la vie quotidienne et la prise de décision. À mesure que la technologie évolue, nous pouvons fournir des prévisions météorologiques plus précises et plus fiables en obtenant des données météorologiques en temps réel. Dans cet article, nous apprendrons comment utiliser la technologie JavaScript et WebSocket pour créer un système efficace de prévisions météorologiques en temps réel. Cet article démontrera le processus de mise en œuvre à travers des exemples de code spécifiques. Nous

See all articles