更改HTML5拖放文件(GMail拖放)的鼠标光标

17

我正在尝试复制GMail处理html5拖放附件的方式--当您将文件拖到页面上时,它会立即显示一个新元素供您放置。我已经解决了这个部分(这并不像我想象的那样简单)。

现在,我想通过在鼠标悬停在除了放置元素以外的任何其他元素上时更改鼠标指针来优化它,以告诉用户此处不能放置。我想我可以使用自定义光标来实现,但似乎这不是GMail正在做的。根据规范,也可以更改鼠标指针,但是我无法正确地使用dropzone/effectAllowed使其正常工作。

如果有帮助就好了,这是我的当前设置:http://jsfiddle.net/guYWx/1/

更新:这是我最终使用的内容: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>

嗨,我自己已经为此苦战数小时了。你的代码比我的好得多。你能解释一下重置时超时延迟的目的是什么吗? - benb
1
它可以防止 dragleave 事件的误判。当你把 dragover/dragleave 绑定到一个带有大量子元素的元素上时,当你从子元素到子元素移动鼠标时,这些事件将被触发。我用调用 reset 来代替了超时,这样你就可以看到拖动时的糟糕情况了:http://jsfiddle.net/guYWx/20/(在 Chrome 中有许多隐藏/显示)。 - Langdon
3个回答

29
通过查看源代码,发现你需要在 dragover 事件处理程序中设置 event.dataTransfer.dropEffect = 'move'; 。通过谷歌搜索 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)

https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/dropEffect - Blaztix

4

@Langdon - 感谢您指出我需要的内容!我已经点赞了。

经过多个小时的努力,我成功地实现了这个建议。

我使用了effectAlloweddropEffect结合起来,在执行拖放操作时提供视觉提示。完全兼容所有浏览器!

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

请问您是否能提供一个可工作的示例?我遇到了一些未定义变量的错误,不确定是您的代码问题还是我的问题。 - ctrlbrk

-3

你需要更改 cursor CSS 属性。

你可以在 这里 找到不同的 cursor 值列表。

你也可以使用 cursor: url('foo.png'); 指定自定义光标图像。


我知道可以更改光标,但GMail并没有这样做。cursor:no-drop和GMail上的光标外观之间有很大的区别。 - Langdon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接