2011-12-10 48 views
12

Tôi đang cố gắng tạo lại cách GMail xử lý các tệp đính kèm kéo/thả html5 - nơi ngay sau khi bạn kéo tệp qua trang, nó sẽ hiển thị phần tử mới cho bạn thả chúng vào. Tôi nhận được phần đó đã được giải quyết (nó không thẳng thắn như tôi nghĩ).Thay đổi con trỏ chuột cho tệp kéo thả HTML5 (Kéo thả Gmail)

Bây giờ tôi đang cố gắng đánh bóng nó bằng cách thay đổi con trỏ chuột khi con chuột vượt qua bất kỳ phần tử nào khác ngoài phần tử thả, để báo cho người dùng bỏ không được phép ở đây. Tôi tưởng tượng tôi có thể làm điều đó với một con trỏ tùy chỉnh, nhưng điều đó dường như không phải là những gì GMail đang làm. The spec sẽ gợi ý rằng có thể thay đổi con trỏ chuột, nhưng tôi không thể làm cho nó hoạt động đúng, sử dụng dropzone/effectAllowed.

Bất kỳ trợ giúp sẽ được đánh giá, đây là thiết lập hiện tại của tôi: http://jsfiddle.net/guYWx/1/

ETA: Đây là những gì tôi đã kết thúc với: http://jsfiddle.net/guYWx/16/

<body style="border: 1px solid black;"> 
    <div id="d0" style="border: 1px solid black;">drag files onto this page</div> 
    <div id="d1" style="border: 1px solid black; display: none; background-color: red;">-&gt; drop here &lt;-</div> 
    <div id="d2" style="border: 1px solid black;">and stuff will happen</div> 
    <div style="float: left;">mouse them all over&nbsp;</div> 
    <div style="float: left;">these elements</div> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <div>end page</div> 
</body> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 
<script type="text/javascript"> 
    var resetTimer; 

    var reset = function() 
    { 
     $('#d1').hide(); 
    }; 

    var f = function(e) 
    { 
     var srcElement = e.srcElement? e.srcElement : e.target; 

     if ($.inArray('Files', e.dataTransfer.types) > -1) 
     { 
      e.stopPropagation(); 
      e.preventDefault(); 

      e.dataTransfer.dropEffect = (srcElement.id == 'd1') ? 'copy' : 'none'; 

      if (e.type == "dragover") 
      { 
       if (resetTimer) 
       { 
        clearTimeout(resetTimer); 
       } 
       $('#d1').show(); 
       console.info('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.types is ' + e.dataTransfer.types + '\n\ne.dataTransfer.files.length is ' + e.dataTransfer.files.length); 

      } 
      else if (e.type == "dragleave") 
      { 
       resetTimer = window.setTimeout(reset, 25); 
      } 
      else if (e.type == "drop") 
      { 
       reset(); 
       alert('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.files.length is ' + (e.dataTransfer.files ? e.dataTransfer.files.length : 0)); 
      } 
     } 
    }; 

    document.body.addEventListener("dragleave", f, false); 
    document.body.addEventListener("dragover", f, false); 
    document.body.addEventListener("drop", f, false); 
</script> 
+0

Xin chào, tôi đã chiến đấu với bản thân mình hàng giờ liền. Mã của bạn hoạt động tốt hơn rất nhiều sau đó tôi. Bạn có thể giải thích mục đích trễ thời gian chờ khi thiết lập lại phục vụ không? – benb

+1

Nó ngăn chặn các kết quả dương tính giả cho sự kiện dragleave. Khi bạn liên kết kéo/kéo đến một phần tử với một loạt các phần tử con, các sự kiện sẽ kích hoạt khi bạn di chuột từ phần tử con đến phần tử con. Tôi đã thay thế thời gian chờ bằng một cuộc gọi để 'đặt lại', vì vậy bạn có thể thấy mức độ xấu khi bạn kéo qua: http://jsfiddle.net/guYWx/20/ (nhiều ẩn/hiển thị trong Chrome). – Langdon

Trả lời

24

Đã đào một số thông qua nguồn và thấy rằng bạn phải đặt event.dataTransfer.dropEffect = 'move'; bên trong trình xử lý sự kiện dragover của mình. Google để tìm dropEffect để đọc thêm và tìm thấy:

dataTransfer.dropEffect

Controls phản hồi mà người dùng được đưa ra trong DragEnter và sự kiện dragover. Khi người dùng di chuột qua phần tử mục tiêu, con trỏ của trình duyệt sẽ cho biết loại hoạt động nào sẽ mất địa điểm (ví dụ: bản sao, di chuyển, v.v.). Hiệu ứng có thể thực hiện trên một trong các giá trị sau : không, sao chép, liên kết, di chuyển.

từ: http://www.html5rocks.com/en/tutorials/dnd/basics/

Edit: Đây là những gì tôi đã kết thúc với: http://jsfiddle.net/guYWx/16/

Đã phải làm một thủ thuật thêm để có được nó làm việc một cách hoàn hảo. Đã làm điều này để dropper sẽ không xuất hiện khi bạn chọn văn bản và kéo nó xung quanh trang:

if ($.inArray('Files', e.dataTransfer.types) > -1) 
-3

Bạn phải thay đổi cursor Thuộc tính CSS.

Bạn tìm thấy danh sách các giá trị khác nhau của cursorhere.

Bạn cũng có thể chỉ định hình ảnh con trỏ tùy chỉnh với cursor: url('foo.png');.

+0

Tôi biết tôi có thể thay đổi con trỏ, nhưng GMail không làm điều này. Có sự khác biệt rất lớn giữa con trỏ: không thả và con trỏ trông như thế nào trên Gmail. – Langdon

4

@Langdon - Cảm ơn bạn đã chỉ ra chính xác những gì tôi cần! Tôi đã upvoted nó.

Sau khi dành quá nhiều giờ, tôi nhận đề xuất đó hoạt động chính xác như dự định.

Tôi đã sử dụng effectAllowed kết hợp với dropEffect để cung cấp tín hiệu thị giác khi thực hiện thao tác kéo thả. Hoàn toàn qua trình duyệt!

$(document).on('dragstart dragenter dragover', function(event) {  
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/ 
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) { 
     // Needed to allow effectAllowed, dropEffect to take effect 
     event.stopPropagation(); 
     // Needed to allow effectAllowed, dropEffect to take effect 
     event.preventDefault(); 

     $('.dropzone').addClass('dropzone-hilight').show();  // Hilight the drop zone 
     dropZoneVisible= true; 

     // http://www.html5rocks.com/en/tutorials/dnd/basics/ 
     // http://api.jquery.com/category/events/event-object/ 
     event.originalEvent.dataTransfer.effectAllowed= 'none'; 
     event.originalEvent.dataTransfer.dropEffect= 'none'; 

     // .dropzone .message 
     if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) { 
      event.originalEvent.dataTransfer.effectAllowed= 'copyMove'; 
      event.originalEvent.dataTransfer.dropEffect= 'move'; 
     } 
    } 
}).on('drop dragleave dragend', function (event) { 
    dropZoneVisible= false; 

    clearTimeout(dropZoneTimer); 
    dropZoneTimer= setTimeout(function(){ 
     if(!dropZoneVisible) { 
      $('.dropzone').hide().removeClass('dropzone-hilight'); 
     } 
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better 
});