由網頁拖放檔案到桌面的神奇方法
Toby
Toby
你有沒有想過到底怎樣可以把檔案由 DOM ELEMENT 拖放下載到桌面?

由本地的檔案管理員或是桌面拖放檔案到網頁上的話大家應該都很容易在一些網站如 facebook 或 youtube 看到可是說由網頁端拖放檔案到桌面就更少見了。

為甚麼我從來都沒看過有網站用這個方法讓使用者下載檔案?

這當然是有原因的,因為這個功能只有 Google Chrome 支援而已。對於不能跨平台用的 API 沒人用那當然很正常吧?但是作為研究最新技術的 imuslab,這個有趣的功能當然要加進去 ArOZ Online 系統吧?但是,要使用這個檔案由網頁拖放到桌面卻是有這麼堆特別要求:

  1. 拖放的元件必須是連接 (<a>)
  2. 元件的 href 一定要填寫不能留空,但是也可以填 javascript:void(0);
  3. draggable 需要設為 true
  4. 不能使用DOM 屬性 ondragstart ,需要使用 JavaScript 來 加 EventListener

如果你的情況符合上面的條件,你就可以把檔案透過這個 <a> Element 拖放到本地檔案系統了。以下為一個簡單的 Example:

$("#element")[0].addEventListener("dragstart",function(evt){
	var targetMime = "plain/text";
		$.ajax({
			url: "media/getMime/?file=" + encodeURIComponent(properties.filepath),
			success: function(data){
				if (data.error !== undefined){
					targetMime = "text/directory";
				}else{
					targetMime = data;
				}
			},
			async: false
		});
	evt.dataTransfer.setData("DownloadURL",targetMime+":"+ properties.filename +":"+ "http://" + location.hostname + ":" + location.port + "/media/?file=" + encodeURIComponent(properties.filepath));
},true);

到這裡有幾點值得注意

  1. MIME Type 必須符合檔案的內容,不然拖放之後會出現 Internet Shortcut 檔案而不是檔案本身
  2. 如果要在 event 裡使用 AJAX,那 Request 必須為 Synchronize ,就好像上面的例子中用來要求取得檔案 MIME Type 的 AJAX request 一樣
  3. 當設定 DownloadURL 參數時時必需使用完整 URL 而不能使用 Relative Path
  4. addEventListener 的 Option 值必須為 true

就是這樣,你就能成功的做出一個可以拖放到桌面的 HTML5 DOM Element 了喔!

19/6/2020 補充

如果你在下載的時候遇到這個問題

失敗 已封鎖的例子

一般是因為以下兩個原因

  1. 你寫入的 URL 不正確或檔案不存在
  2. 上面的例子裡的一個小 Bug (Hard code 了 http 的問題)

對於非 http 的使用者來說,你可以把這一行

evt.dataTransfer.setData("DownloadURL",targetMime+":"+ properties.filename +":"+ "http://" + location.hostname + ":" + location.port + "/media/?file=" + encodeURIComponent(properties.filepath));

改成

evt.dataTransfer.setData("DownloadURL",targetMime+":"+ properties.filename +":"+ location.protocol + "//" + location.hostname + ":" + location.port + "/media/?file=" + encodeURIComponent(properties.filepath));

(注意多出來的 location.protocol)
來自動 Detect 目前是使用 http: 還是 https: 協議