淺談瀏覽器的原生拖拽事件

雖然之前有寫過模擬瀏覽器拖拽行為的組件,但這種拖拽僅限于改變 DOM 元素的位置,只是 UI 層面的交互效果。最近在做的拖拽上傳文件,拖拽時需要和服務端進行數據層面的交互,此時就需要用到瀏覽器原生的拖拽事件。

在高級瀏覽器中,DOM 元素都有一個 draggable 屬性,用于標記其是否可以在瀏覽器中拖拽,常見的 a 、img 元素的 draggable 默認值為 true,瀏覽器默認其是可以拖拽的,而其他的布局元素如 div、p 這些默認并不支持拖拽,所以值是 false,如果想讓其可以拖動,需要先將其設置成 true。

再來看看原生的拖拽相關的事件類型:

  • drag : 元素被拖拽時由拖拽元素頻繁觸發的事件(每隔幾百毫秒就會觸發一次)
  • dragstart : 拖拽時開始時由拖拽元素觸發的事件
  • dragend : 拖拽結束時觸發由拖拽元素的事件
  • dragover : 當拖拽元素進入放置區域時由放置元素頻繁觸發的事件(每隔幾百毫秒就會觸發一次)
  • dragenter : 當拖拽元素進入放置區域時由放置元素觸發的事件
  • dragleave : 當拖拽元素離開放置區域時由放置元素觸發的事件
  • drop : 當拖拽元素在放置區域放置時由放置元素觸發的事件

將一個文件拖拽并放置到瀏覽器中,瀏覽器默認會觸發 drop 事件,為了阻止瀏覽器默認的放置事件,需要在 dragover 和 drop 事件中進行阻止。

在 IE10 以下的瀏覽器中,并不是完全不支持,只是支持程度有限,沒有可玩性,這里就不多說了。

在高級瀏覽器中拖拽事件接口的對象中都有一個高級對象 dataTransfer,拖拽的數據就保存在這個對象中,正因為拖拽時能傳遞數據才有了可玩性,可見該對象的重要程度。HTML5 中關于拖拽相關的高級功能都是通過該對象來實現的。

常見的拖拽上傳需要從系統向瀏覽器拖進一個文件,該文件就保存在 dataTransfer 中,在放置的時候就可以通過該對象來讀取文件,代碼如下:


    document.addEventListener( 'dragover', function( e ){
        // 阻止默認事件的觸發
        e.preventDefault();
    }, false );

    document.addEventListener( 'drop', function( e ){
        var dt = e.dataTransfer,
            item, reader;

        // 阻止默認事件的觸發
        e.preventDefault();

        if( dt && dt.files ){
            item = dt.files[0];

            // 通過使用FileReader構造器來讀取該文件
            reader = new FileReader();

            // 讀取文件后將base64的數據傳遞給隱藏的輸入框并做提交
            reader.onload = function( e ){
                // e.target.result 中就包含了讀取到的文件信息           
            };

            // 讀取文件
            reader.readAsDataURL( item );
        }
    }, false );

上面是從系統向瀏覽器拖入文件的處理方法,那么對于頁面中本身存在的元素,該如何處理呢?

HTML5 的 dataTransfer 對象在各高級瀏覽器中的表現還是有所差異的,比如對于直接拖拽頁面中的圖片然后讀取圖片信息,有些瀏覽器并不支持,或者是太麻煩,我就沒去做嘗試了,如果有深究過的可以告訴我。

在頁面中的圖片,本身都有一個 URL,在開始拖拽的時候將拖拽的數據設置成圖片的 URL,然后在放置的時候讀取這個 URL,最后將這個 URL 提交給服務端,讓服務端去下載該圖即可。

在拖拽開始時使用 setData 方法設置拖拽數據為圖片的 URL:


    <img src="http://example.com/test.jpg" alt="" id="testImg" />

    var testImg = document.getElementById( 'testImg' );

    testImg.addEventListener( 'dragstart', function( e ){
        var dt = e.dataTransfer;

        if( dt ){
            // 將圖片的URL設置成拖拽數據的文本類型
            dt.setData( 'text', this.src );
        }
    }, false );

在放置的時候使用 getData 方法來獲取數據:


    document.addEventListener( 'drop', function( e ){
        var dt = e.dataTransfer,
            src;

        if( dt ){
            src = dt.getData( 'text' );

            // 將 URL 提交給服務端
        }
    }, false );

如果 img 標簽包含在 a 標簽中,想讓這些圖片元素也支持拖拽傳遞圖片 URL,需要給 a 元素綁定 dragstart 事件,然后使用 setData 方法將圖片的 URL 存儲進去。因為 a 元素默認拖拽的時候傳遞的是其自身的鏈接。

高級瀏覽器在使用 setData、getData 方法在設置和讀取拖拽的數據類型時都支持好幾種數據格式,常見的如 text/plain,而唯獨 IE10 只支持 text 格式,為了兼容性,沒有特殊情況的話還是得老老實實設置成 text 格式。

有了 setData、getData 方法,就可以在拖拽和放置時很方便的傳遞數據,高級瀏覽器支持的類型更多,有更多的可能。


所屬標簽

無標簽

25选5玩法中奖