首頁  >  文章  >  web前端  >  談對JavaScript原生拖放的深入理解

談對JavaScript原生拖放的深入理解

高洛峰
高洛峰原創
2017-01-18 13:31:351064瀏覽

前面的話

  拖放(drag-and-drop,DnD)其實是兩個動作-拖曳和放。所以,它牽涉到兩個元素。一個是被拖的元素,稱為拖放源;另一個是要放的目標,稱為拖放目標。本文將透過分割這兩個概念來詳細介紹原生拖放

拖放源

  什麼樣的元素才是拖放源呢?

  HTML5為所有HTML元素規定了一個draggable屬性,表示元素是否可以拖曳

  映像和連結的draggable屬性自動被設定成了true,而其他元素這個屬性的預設值都是fal
[注意]必須設定draggable='true'才能生效,只設定draggable不起作用


  預設情況下,文字只有在被選中的情況下才能拖曳,而圖像和連結在任何時候都可以拖曳。而其他元素則無法被拖放

<input value="文字可拖动">
<img alt="图像可拖动" src="http://files.cnblogs.com/files/xiaohuochai/zan.gif">
<a href="#">链接可拖动</a>
<div id="test" style="height:30px;width:300px;background:pink;">元素不可拖动</div>

  當為元素設定draggable屬性後,普通元素也可以拖曳

<div draggable="true" style="height:30px;width:100px;background:pink;"></div>

相容處理程序調用dragDrop()方法來實現拖動效果

<div id="test" style="height:30px;width:300px;background:pink;"></div>
<script>
test.onmousedown = function(){
this.dragDrop();
}
</script>


  [注意]如果讓firefox支持draggable屬性,必須添加一個ondragstart事件處理程序,並在dataTransfer對象使用setData()方法來啟動效果

拖放事件


  拖放源涉及到3個拖放事件。拖曳拖曳來源時,依序觸發dragstart、drag和dragend這3個事件


dragstart


  按下滑鼠鍵並開始移動滑鼠時,會在被拖曳的元素上觸發拖曳事件。此時間標變成「不能放」符號(圓環中有一條反斜線),表示不能把元素放到自己上面


drag


  觸發dragstart事件後,隨即會觸發drag事件,而且在元素元素被拖曳期間會持續觸發該事件


dragend


  當拖動停止時(無論是把元素放到了有效的放置目標,還是放到了無效的放置目標上),會觸發dragend事件

<div id="test" draggable="true" style="height:30px;width:100px;background:pink;">0</div>
<script>
var timer,i=0;
test.ondragstart = function(){
this.style.backgroundColor = &#39;lightgreen&#39;;
}
test.ondrag = function(){
if(timer) return;
timer = setInterval(function(){
test.innerHTML = i++;
},100)
}
test.ondragend = function(){
clearInterval(timer);
timer = 0;
this.style.backgroundColor = &#39;pink&#39;;
}
</script>

<div id="test" draggable="true" style="height:30px;width:130px;background:pink;float:left;">拖放源</div>
<div id="target" style="float:right;height: 200px;width:200px;background:lightblue;">拖放目标</div>
<script>
var timer,i=0;
var timer1,i1=0;
//兼容IE8-浏览器
test.onmousedown = function(){
if(this.dragDrop){
this.dragDrop();
}
}
test.ondragstart = function(){
this.style.backgroundColor = &#39;lightgreen&#39;;
this.innerHTML = &#39;开始拖动&#39;;
}
test.ondrag = function(){
if(timer) return;
timer = setInterval(function(){
test.innerHTML = &#39;元素已被拖动&#39; + ++i + &#39;秒&#39;;
},1000);
}
test.ondragend = function(){
clearInterval(timer);
timer = 0;i =0;
this.innerHTML = &#39;结束拖动&#39;;
this.style.backgroundColor = &#39;pink&#39;;
}
target.ondragenter = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
this.innerHTML = &#39;有元素进入目标区域&#39;;
this.style.background = &#39;red&#39;;
}
target.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
if(timer1) return;
timer1 = setInterval(function(){
target.innerHTML = &#39;元素已进入&#39; + (++i1) + &#39;秒&#39;;
},1000);
}
target.ondragleave = function(){
clearInterval(timer1);
timer1 = 0;i1=0;
this.innerHTML = &#39;元素已离开目标区域&#39;;
this.style.backgroundColor = &#39;lightblue&#39;;
}
target.ondrop = function(){
clearInterval(timer1);
timer1 = 0;i1=0;
this.innerHTML = &#39;元素已落在目标区域&#39;;
this.style.backgroundColor = &#39;orange&#39;;
}
</script>

<div>请将从这堆内容不同乱七八糟的文字中挑选一些移动到拖放目标中</div>
<div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div>
<div id="result"></div>
<script>
target.ondragenter = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
this.innerHTML = &#39;有元素进入目标区域&#39;;
this.style.background = &#39;red&#39;;
}
target.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
}
target.ondragleave = function(e){
e = e || event;
this.innerHTML = &#39;元素已离开目标区域&#39;;
this.style.backgroundColor = &#39;lightblue&#39;;
}
target.ondrop = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
result.innerHTML = &#39;落入目标区域的文字为:&#39; + e.dataTransfer.getData(&#39;text&#39;);
this.innerHTML = &#39;元素已落在目标区域&#39;;
this.style.backgroundColor = &#39;orange&#39;;
}
</script>

拖放目標

  拖放目標是指被拖曳的元素鬆開滑鼠時被放置的目標


  拖放來源被拖曳到拖曳到拖曳到目標上時,將依序觸發目標和dragleave或drop這四個事件


dragenter


  只要有元素被拖曳到放置目標上,觸發dragenter事件


dragover


㟎持續觸發dragover事件


dragleave


  如果元素被拖出了放置目標,觸發dragleave事件


drop


 㜀㟎。 ox瀏覽器的drop事件的預設行為是開啟被放到放置目標上的URL。為了讓firefox支援正常的拖放,也要取消drop事件的預設行為


  預設情況下,目標元素是不允許被放置的,所以不會發生drop事件。只要在dragover和dragenter事件中阻止預設行為,才能成為被允許的放置目標,才能允許發生drop事件。此時,遊標變成了允許放置的符號

<div id="test" draggable="true" data-value="这是一个秘密" style="height:30px;width:100px;background:pink;">拖动源</div>
<div id="target" style="margin-top:20px;height: 100px;width:200px;background:lightblue;">拖放目标</div>
<div id="result"></div>
<script>
//兼容IE8-浏览器
test.onmousedown = function(){
if(this.dragDrop){
this.dragDrop();
}
}
test.ondragstart = function(e){
e = e || event;
e.dataTransfer.setData(&#39;text&#39;,test.getAttribute(&#39;data-value&#39;));
}
target.ondragenter = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
this.innerHTML = &#39;有元素进入目标区域&#39;;
this.style.background = &#39;red&#39;;
}
target.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
}
target.ondragleave = function(e){
e = e || event;
this.innerHTML = &#39;元素已离开目标区域&#39;;
this.style.backgroundColor = &#39;lightblue&#39;;
}
target.ondrop = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
result.innerHTML = &#39;落入目标区域的文字为:&#39; + e.dataTransfer.getData(&#39;text&#39;);
this.innerHTML = &#39;元素已落在目标区域&#39;;
this.style.backgroundColor = &#39;orange&#39;;
}
</script>
   
改变光标
  利用dataTransfer对象,不仅可以传输数据,还能通过它来确定被拖动的元素以及作为放罝目标的元素能够接收什么操作。为此,需要访问dataTransfer对象的两个属性:dropEffect和effectAllowed
  实际上,这两个属性并没有什么用,只是拖动源在拖动目标上移动时,改变不同的光标而已(但是,有一种情况除外)
dropEffect
  dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列4个可能的值
  "none":不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值(此时,将无法触发drop事件)
  "move":应该把拖动的元素移动到放置目标
  "copy":应该把拖动的元素复制到放置目标
  "link":表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)
  在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号
  [注意]必须在ondragover事件处理程序中针对放置目标来设置dropEffect属性
effectAllowed
  dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖动元素的哪种dropEffect
  effectAllowed属性可能的值如下
  "uninitialized":没有给被拖动的元素设置任何放置行为
  "none":被拖动的元素不能有任何行为 
 "copy":只允许值为"copy"的dropEffect
  "link"只允许值为"link"的dropEffect
  "move":只允许值为"move"的dropEffect
  "copyLink":允许值为"copy"和"link"的dropEffect
  "copyMove":允许值为"copy"和"move"的dropEffect
  "linkMove":允许值为"link"和"move"的dropEffect
 "all":允许任意dropEffect
  [注意]必须在ondragstart事件处理程序中设置effectAllowed属性

   


dataTransfer對象

  為了在拖放操作時實現數據交換,引入了dataTransfer

  為了在拖放操作時實現數據交換,引入了dataTransfer

  為了在拖放操作時實現數據從拖曳元素向放置目標傳遞字串格式的資料


  dataTransfer物件有兩個主要方法:getData()和setData()


  getData()可以取得由setData()儲存的值。 setData()方法的第一個參數,也是getData()方法唯一的一個參數,是一個字串,表示保存的資料類型,取值為"text"或"URL"


  IE只定義了"text "和"URL"兩種有效的資料類型,而HTML5則對此加以擴展,允許指定各種MIME類型。考慮到向後相容,HTML5也支援"text"和"URL",但這兩種類型會被映射為"text/plain"和"text/uri-list"


  實際上,dataTransfer物件可以為每種MIME類型都會儲存一個值。換句話說,同時在這個物件中保存一段文字和一個URL不會有任何問題


  [注意]保存在dataTransfer物件中的資料只能在drop事件處理程序中讀取


  在拖曳文字方塊中的文字時,瀏覽器會呼叫setData()方法,將拖曳的文字以"text"格式儲存在dataTransfer物件中。類似地,在拖放連結或圖像時,會呼叫setData()方法並儲存URL。然後,當這些元素拖曳到放置目標時,就可以透過getData()讀到這些資料

<div id="test" draggable="true" style="height:30px;width:100px;background:pink;display:inline-block;">拖放源</div>
<br>
<div id="target1" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(none)拖放目标</div>
<div id="target2" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(move)拖放目标</div>
<div id="target3" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(copy)拖放目标</div>
<div id="target4" style="margin-top:20px;height: 100px;width:150px;background:lightblue;display:inline-block;">(link)拖放目标</div>
<div id="result"></div>
<script>
//兼容IE8-浏览器
test.onmousedown =function(){
if(this.dragDrop){
this.dragDrop();
}
}
test.ondragstart = function(e){
e = e || event;
//兼容firefox浏览器
e.dataTransfer.setData(&#39;text&#39;,&#39;&#39;);
e.dataTransfer.effectAllowed = &#39;all&#39;;
}
target1.ondragenter = target2.ondragenter =target3.ondragenter =target4.ondragenter =function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}this.style.background = &#39;red&#39;;
}
target1.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
e.dataTransfer.dropEffect = &#39;none&#39;;
}
target2.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
e.dataTransfer.dropEffect = &#39;move&#39;;
}
target3.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
e.dataTransfer.dropEffect = &#39;copy&#39;;
}
target4.ondragover = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
e.dataTransfer.dropEffect = &#39;link&#39;;
}
target1.ondragleave = target2.ondragleave =target3.ondragleave =target4.ondragleave =function(e){
e = e || event; this.style.backgroundColor = &#39;lightblue&#39;;
}
target1.ondrop = target2.ondrop =target3.ondrop =target4.ondrop =function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
this.style.backgroundColor = &#39;orange&#39;;
}
</script>

   

  當然,也可以在dragstart事件處理程序中呼叫setData(),手動儲存自己要傳輸的數據,以便將來使用

rrreeerrreee

以上所述是小編給大家介紹的JavaScript原生拖放,希望對大家有幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對PHP中文網的支持!

更多談談對JavaScript原生拖放的深入理解相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn