Изменение курсора мыши для файлов перетаскивания HTML5 (GMail Drag Drop)

Я пытаюсь воспроизвести способ, которым GMail обрабатывает html5-файлы перетаскивания вложений - где, как только вы перетаскиваете файлы поверх страницы, он отображает новый элемент, куда вы можете их перетаскивать. Я выполнил эту часть (это было не так просто, как я думал, что будет).

Теперь я пытаюсь исправить ситуацию, изменив курсор мыши, когда мышь находится над любым другим элементом, кроме элемента drop, чтобы сообщить, что удаление пользователя здесь запрещено. Я думаю, что могу сделать это с помощью пользовательского курсора, но это не похоже на то, что делает GMail. Спецификация предполагает, что возможно также изменить курсор мыши, но я не могу заставить его работать правильно, используя dropzone/effectAllowed.

Любая помощь будет оценена, вот мои текущие настройки: http://jsfiddle.net/guYWx/1/

ETA: Вот чем я закончил: 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>

3 ответа

Решение

Пробежался по источнику и обнаружил, что должен установить event.dataTransfer.dropEffect = 'move'; внутри вашего dragover обработчик события. Погуглил для dropEffect чтобы узнать больше и нашел:

dataTransfer.dropEffect

Управляет обратной связью, которую пользователь получает во время событий dragenter и dragover. Когда пользователь наводит курсор на целевой элемент, курсор браузера будет указывать, какой тип операции будет выполняться (например, копирование, перемещение и т. Д.). Эффект может принимать одно из следующих значений: none, copy, link, move.

от: http://www.html5rocks.com/en/tutorials/dnd/basics/

Редактировать: вот что я закончил: http://jsfiddle.net/guYWx/16/

Пришлось сделать еще один трюк, чтобы все заработало идеально. Сделал так, чтобы пипетка не появлялась при выделении текста и перетаскивании его по странице:

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

@Langdon - Спасибо, что указали именно то, что мне нужно! Я проголосовал за это.

Потратив так много часов, я понял, что это предложение работает точно так, как задумано.

Я использовал effectAllowed в сочетании с dropEffect для предоставления визуальных подсказок при выполнении операций перетаскивания. Полностью кросс-браузерный!

$(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
});

Вы должны изменить cursor CSS свойство

Вы найдете список различных значений cursor здесь

Вы также можете указать пользовательское изображение курсора с помощью cursor: url('foo.png');,

Другие вопросы по тегам