深入理解javascript原生拖放

来源:http://www.cnblogs.com/xiaohuochai/archive/2016/09/19/5886618.html
-Advertisement-
Play Games

[1]拖放源 [2]拖放目標 [3]dataTransfer對象 [4]改變游標 ...


×
目錄
[1]拖放源 [2]拖放目標 [3]dataTransfer對象[4]改變游標

前面的話

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

 

拖放源

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

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

  圖像和鏈接的draggable屬性自動被設置成了true,而其他元素這個屬性的預設值都是false

  [註意]必須設置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>

相容

  IE9-瀏覽器不支持draggable屬性,但可通過mousedown事件處理程式調用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

  按下滑鼠鍵並開始移動滑鼠時,會在被拖放的元素上觸發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 = 'lightgreen';
}
test.ondrag = function(){
    if(timer) return;
    timer = setInterval(function(){
        test.innerHTML =  i++;
    },100)
}
test.ondragend = function(){
    clearInterval(timer);
    timer = 0;
    this.style.backgroundColor = 'pink';
}
</script>

拖放目標

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

  拖放源被拖動到拖放目標上時,將依次觸發dragenter、dragover和dragleave或drop這四個事件

dragenter

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

dragover

  被拖動的元素在放置目標的範圍內移動時,持續觸發dragover事件

dragleave

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

drop

  如果元素被放到了放置目標中,觸發drop事件

  [註意]firefox瀏覽器的drop事件的預設行為是打開被放到放置目標上的URL。為了讓firefox支持正常的拖放,還要取消drop事件的預設行為

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

<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 = 'lightgreen';
    this.innerHTML = '開始拖動';
}
test.ondrag = function(){
    if(timer) return;
    timer = setInterval(function(){
        test.innerHTML =  '元素已被拖動' + ++i + '';
    },1000);
}
test.ondragend = function(){
    clearInterval(timer);
    timer = 0;i =0;
    this.innerHTML = '結束拖動';
    this.style.backgroundColor = 'pink';
}
target.ondragenter = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    this.innerHTML = '有元素進入目標區域';
    this.style.background = 'red';
}
target.ondragover = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    if(timer1) return;
    timer1 = setInterval(function(){
        target.innerHTML =  '元素已進入' + (++i1) + '';
    },1000);
}
target.ondragleave = function(){
    clearInterval(timer1);
    timer1 = 0;i1=0;
    this.innerHTML = '元素已離開目標區域';
    this.style.backgroundColor = 'lightblue';
}
target.ondrop = function(){
    clearInterval(timer1);
    timer1 = 0;i1=0;
    this.innerHTML = '元素已落在目標區域';
    this.style.backgroundColor = 'orange';    
}
</script>

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>請將從這堆內容不同亂七八糟的文字中挑選一些移動到拖放目標中</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 = '有元素進入目標區域';
    this.style.background = 'red';
}
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 = '元素已離開目標區域';
    this.style.backgroundColor = 'lightblue';
}
target.ondrop = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    result.innerHTML = '落入目標區域的文字為:' + e.dataTransfer.getData('text');
    this.innerHTML = '元素已落在目標區域';
    this.style.backgroundColor = 'orange';    
}
</script>

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

<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('text',test.getAttribute('data-value'));
}
target.ondragenter = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    this.innerHTML = '有元素進入目標區域';
    this.style.background = 'red';
}
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 = '元素已離開目標區域';
    this.style.backgroundColor = 'lightblue';
}
target.ondrop = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    result.innerHTML = '落入目標區域的文字為:' + e.dataTransfer.getData('text');
    this.innerHTML = '元素已落在目標區域';
    this.style.backgroundColor = 'orange';    
}
</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屬性

<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('text','');
      e.dataTransfer.effectAllowed = 'all';
}
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 = 'red';
}
target1.ondragover = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    e.dataTransfer.dropEffect = 'none';
}
target2.ondragover = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    e.dataTransfer.dropEffect = 'move';
}
target3.ondragover = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    e.dataTransfer.dropEffect = 'copy';
}
target4.ondragover = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
    e.dataTransfer.dropEffect = 'link';
}
target1.ondragleave = target2.ondragleave =target3.ondragleave =target4.ondragleave =function(e){
    e 
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 有IOS的開關模擬,當然也有MIUI的開關模擬 看到設置選項裡面的開關樣式,突發奇想地來試試 最終效果如圖: 實現過程 1. 選項框checkbox 模擬開關當然需要一個選項框,這裡用到了覆選框checkbox 2. 理解開關的過程 點擊開關按鈕,則開啟或關閉。原生的checkbox無法做到圖示的效 ...
  • 1.佈局 ① 使用 <div> 元素的 HTML 佈局,<div> 元素常用作佈局工具,因為能夠輕鬆地通過 CSS 對其進行定位。 ② 使用 HTML5 的網站佈局 HTML5 提供的新語義元素定義了網頁的不同部分: HTML5 語義元素: ③ 使用表格的 HTML 佈局 。<table> 元素不是 ...
  • 一、簡介 該demo主要實現QQ分享、微信分享和新浪微博分享。(調試包請到論壇掃描對應二維碼下載) 二、效果圖 三、相關討論 http://bbs.deviceone.net/forum.php?mod=viewthread&tid=852&extra=page%3D1 四、源碼地址 https:/ ...
  • 用js封裝一些常用的jquery方法 記錄一下 hasClass:判斷是否有class addClass:增加class removeClass:移除class ...
  • 這是我寫的關於列表組件的第4篇博客。前面的相關文章有: 1. 列表組件抽象(1)-概述 2. 列表組件抽象(2)-listViewBase說明 3. 列表組件抽象(3)-分頁和排序管理說明 本文介紹列表組件中我對滾動列表及滾動分頁的實現思路。 在pc端,通過滾動進行翻頁的需求非常常見;移動端也是,只 ...
  • 在做網頁相容時 發現在ie8下的input內用padding失效 為了達到居中文字的效果 使用line-height可以解決問題 ...
  • 前端是一個承上啟下的職位,正因為其位置的特殊性導致其必須瞭解設計和後臺的一些基本知識。本文並非教大家如何取代設計的工作,而是講解前端如何更快更便捷的實現一些簡單的設計任務,在沒有設計師的情況下如何利用工具解決UI呈現的問題,讓工作事半功倍。 Photoshop使用 大多數前端工程師都有過切圖的經歷, ...
  • QRCode.js 是一個用於生成二維碼圖片的插件。 github地址 QRCode.js 是一個用於生成二維碼圖片的插件。 github地址 github地址 github地址 github地址 線上實例 實例預覽 基礎示例 實例預覽 API 介面 使用方法 載入 JavaScript 文件 <s ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...