2015-01-29 20 views
11

Khi viết ứng dụng web đã nhập tệp, tôi muốn sử dụng kéo thả 'n', nhưng tôi không muốn chỉ một vùng thả nhỏ trên trang. Tôi nghĩ rằng nó sẽ thuận tiện hơn nếu bạn có thể thả bất cứ nơi nào trên trang. May mắn thay, sự kiện window.ondrop kích hoạt bất cứ nơi nào trên trang, nhưng tôi muốn có một số hiệu ứng lạ mắt để hiển thị trực quan người dùng rằng việc kéo/thả là có thể.Toàn bộ trang làm vùng thả để kéo và thả

Để làm điều đó, tất cả những gì là cần thiết là phát hiện khi một tệp được kéo vào cửa sổ, và khi nó được kéo ra khỏi, để kích hoạt hiệu ứng cho thấy người sử dụng mà ứng dụng đã kéo kích hoạt. Chỉ ra rằng các sự kiện kéo không thuận tiện. Tôi giả định rằng window.ondragenter sẽ chỉ kích hoạt một lần, khi người dùng đã nhập trang. Sau đó, khi bạn rời khỏi cửa sổ, nó sẽ kích hoạt window.ondragleave. Sai rồi. Nó liên tục bắn khi chuột di chuyển qua các phần tử con trong trang.

Tôi đã xem những thuộc tính nào có sẵn trong đối tượng sự kiện, cố tìm bất kỳ thứ gì có thể cô lập những gì tôi cần, nhưng không có gì hiệu quả. Tôi nhận được nhiều nhất là có thể thay đổi màu nền của body. Và chỉ khi không có gì khác trên trang.

Tấn các trang tải lên tệp đã đúng. Ví dụ: Imgur và WeTransfer. Các trang web của họ đều được mã hóa và nén thành spahetti đến mức không thể đọc được, và tôi không thể tìm thấy bất cứ điều gì về chủ đề này bằng cách googling.

Vậy làm cách nào để thực hiện điều này?

Trả lời

17

Bí quyết là sử dụng vùng thả bao phủ toàn bộ trang và lưu vào bộ nhớ cache target của window.ondragenter để so sánh với target của window.ondragleave.

Thứ nhất, vùng thả:

<style> 
div.dropzone 
{ 
    /* positions to point 0,0 - required for z-index */ 
    position: fixed; top: 0; left: 0; 
    /* above all elements, even if z-index is used elsewhere 
     it can be lowered as needed, but this value surpasses 
     all elements when used on YouTube for example. */ 
    z-index: 9999999999;    
    /* takes up 100% of page */ 
    width: 100%; height: 100%;   
    /* dim the page with 50% black background when visible */ 
    background-color: rgba(0,0,0,0.5); 
    /* a nice fade effect, visibility toggles after 175ms, opacity will animate for 175ms. note display:none cannot be animated. */ 
    transition: visibility 175ms, opacity 175ms; 
} 
</style> 
<!-- both visibility:hidden and display:none can be used, 
    but the former can be used in CSS animations --> 
<div style="visibility:hidden; opacity:0" class="dropzone"></div> 

Mặc dù vùng thả sẽ được bao phủ toàn bộ trang, sử dụng visibility:hidden hoặc display:none sẽ giấu nó khỏi tầm nhìn. Tôi đã sử dụng visibility:hidden để hoạt ảnh CSS có thể được sử dụng để tạo hiệu ứng chuyển tiếp.

Gán sự kiện

<script> 
/* lastTarget is set first on dragenter, then 
    compared with during dragleave. */ 
var lastTarget = null; 

window.addEventListener("dragenter", function(e) 
{ 
    lastTarget = e.target; // cache the last target here 
    // unhide our dropzone overlay 
    document.querySelector(".dropzone").style.visibility = ""; 
    document.querySelector(".dropzone").style.opacity = 1; 
}); 

window.addEventListener("dragleave", function(e) 
{ 
    // this is the magic part. when leaving the window, 
    // e.target happens to be exactly what we want: what we cached 
    // at the start, the dropzone we dragged into. 
    // so..if dragleave target matches our cache, we hide the dropzone. 
    if(e.target === lastTarget || e.target === document) 
    { 
     document.querySelector(".dropzone").style.visibility = "hidden"; 
     document.querySelector(".dropzone").style.opacity = 0; 
    } 
}); 
</script> 

Vì vậy, đây là quá trình: Bạn kéo một tập tin qua cửa sổ, và ngay lập tức window.ondragenter cháy. target được đặt thành phần tử gốc, <html>. Sau đó, bạn ngay lập tức bỏ ẩn vùng thả của mình, bao gồm toàn bộ trang. window.ondragenter sẽ kích hoạt lại, lần này mục tiêu là dropzone của bạn. Mỗi khi sự kiện dragenter kích hoạt, nó sẽ lưu vào bộ nhớ cache, vì đây sẽ là mục tiêu phù hợp với sự kiện window.ondragleave cuối cùng kích hoạt khi bạn kéo ra khỏi cửa sổ.

Tại sao tính năng này hoạt động? Tôi không có ý tưởng, nhưng đó là cách để làm điều đó. Điều này là khá nhiều phương pháp làm việc chỉ kích hoạt khi người dùng kéo ra khỏi trang.

Tôi tin rằng nó hoạt động vì một khi dropzone được ẩn, nó sẽ luôn là là mục tiêu cuối cùng. Nó bao gồm mọi pixel của trang, ngay cả thẻ <html>. Phương pháp này dựa vào việc kéo thả khi thoát khỏi cửa sổ. Thật không may là có một bug in Firefox ngăn nó hoạt động bình thường.Vui lòng bỏ phiếu cho nó để nó sẽ được sửa chữa sớm hơn. Kể từ Firefox 57.0.2, dragleave xuất hiện để kích hoạt đúng cách. Tuy nhiên, một cách giải quyết là cần thiết, kiểm tra document thay vì các yếu tố cache:

if(e.target === lastTarget || e.target === document) 

Here's a JSBin of it in action. Được thử nghiệm trong Chrome, Firefox, Edge và IE11 mới nhất.

+0

Điều này không hoạt động trong Firefox, vì event.target được trả về bởi dragleave là tài liệu HTML, không khớp với phần tử được lưu trong bộ nhớ cache cuối cùng (rất có thể là .dropzone). –

+0

@DannyLin Thật không may có một [lỗi trong Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=656164) ngăn không cho nó hoạt động đúng cách. Vui lòng bỏ phiếu cho nó để nó sẽ được sửa chữa sớm hơn. – bryc

+0

Ah, vì vậy lỗi này có vẻ đã được sửa? Firefox trả về một cách đáng tin cậy 'document' như' event.target' khi rời khỏi cửa sổ. Tôi đưa giải pháp này vào câu trả lời. – bryc