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

Posted

技术标签:

【中文标题】更改 HTML5 拖放文件的鼠标光标(GMail 拖放)【英文标题】:Changing Mouse Cursor for HTML5 Drag Drop Files (GMail Drag Drop) 【发布时间】:2012-01-17 14:13:02 【问题描述】:

我正在尝试重现 GMail 处理 html5 拖放附件的方式——只要您将文件拖到页面上,它就会显示一个新元素供您放置它们。我解决了这部分问题(它并不像我想象的那么简单)。

现在我试图通过在鼠标悬停在除放置元素之外的任何其他元素上时更改鼠标光标来完善它,以告诉用户此处不允许放置。我想我可以使用自定义光标来完成,但这似乎不是 GMail 正在做的事情。 The spec 建议也可以更改鼠标光标,但我似乎无法使用 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>

【问题讨论】:

嗨,我自己已经为此奋斗了好几个小时。你的代码比我的要好得多。你能解释一下重置超时延迟的目的吗? 它可以防止dragleave事件的误报。当您将 dragover/dragleave 绑定到具有一堆子元素的元素时,当您将鼠标从子元素移到子元素时,事件将触发。我用对reset 的调用替换了超时,所以当你拖过去时,你可以看到它有多糟糕:jsfiddle.net/guYWx/20(在 Chrome 中隐藏/显示很多)。 【参考方案1】:

您必须更改cursor CSS 属性。

您会找到cursor here 的不同值的列表。

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

【讨论】:

我知道我可以更改光标,但 GMail 不这样做。 cursor:no-drop 与 GMail 上的光标外观之间存在巨大差异。【参考方案2】:

对源代码进行了一些挖掘,发现您应该在 dragover 事件处理程序中设置 event.dataTransfer.dropEffect = 'move';。谷歌搜索 dropEffect 以了解更多信息并找到:

dataTransfer.dropEffect

控制在拖动过程中给用户的反馈和 拖拽事件。当用户将鼠标悬停在目标元素上时, 浏览器的光标将指示要执行的操作类型 地点(例如副本、移动等)。效果可以采取其中一种 以下值:无、复制、链接、移动。

来自:http://www.html5rocks.com/en/tutorials/dnd/basics/

编辑:这是我最终得到的结果:http://jsfiddle.net/guYWx/16/

必须做一个额外的技巧才能让它完美地工作。这样做是为了在您选择文本并将其拖到页面上时不会出现滴管:

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

【讨论】:

developer.mozilla.org/en-US/docs/Web/API/DataTransfer/…【参考方案3】:

@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
);

【讨论】:

能否请您发布一个工作示例,我收到未定义变量的错误,我不确定是您的代码还是我的代码。

以上是关于更改 HTML5 拖放文件的鼠标光标(GMail 拖放)的主要内容,如果未能解决你的问题,请参考以下文章

更改html5拖放功能,使元素看起来附加到光标[重复]

拖放时更改鼠标光标

UWP - 有没有办法在退出 ListView 时更改鼠标光标而不在拖放期间触发事件?

在 HTML5 中拖动时如何更改光标图标?

文件拖放 HTML5 问题

「萌新上手Mac」关于MacBook拖放技巧