【问题标题】:How do I detect a file is being dragged rather than a draggable element on my page?如何检测正在拖动的文件而不是页面上的可拖动元素?
【发布时间】:2011-10-14 10:50:27
【问题描述】:

我正在使用 html5 事件来启用文件和元素的拖放。我已将 dragover 事件附加到正文,并使用事件委托来显示可以拖放可拖动对象的位置。我的问题是如何判断文件是否被拖动与具有可拖动 = true 的元素。我知道我可以检测到通过 e.target 拖动的元素。但是,我怎么知道它是否是一个文件。

jquery 可用。

另外,不是在这里谈论 jquery-ui 可拖动。

我开始认为检测文件的唯一方法可能是通过排除和检测元素。如果我们不拖动元素,假设它是一个文件。这将需要额外的工作,因为默认情况下图像和链接是可拖动的,所以我必须向它们添加事件或阻止它们拖动。

【问题讨论】:

    标签: javascript html drag-and-drop


    【解决方案1】:

    您可以通过检查dataTransfer.types 来检测正在拖动的内容。这种行为在浏览器之间(还)不一致,因此您必须检查 'Files' (Chrome) 和 'application/x-moz-file' (Firefox) 是否存在。

    // Show the dropzone when dragging files (not folders or page
    // elements). The dropzone is hidden after a timer to prevent 
    // flickering to occur as `dragleave` is fired constantly.
    var dragTimer;
    $(document).on('dragover', function(e) {
      var dt = e.originalEvent.dataTransfer;
      if (dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))) {
        $("#dropzone").show();
        window.clearTimeout(dragTimer);
      }
    });
    $(document).on('dragleave', function(e) {
      dragTimer = window.setTimeout(function() {
        $("#dropzone").hide();
      }, 25);
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="dropzone" style="border: 2px dashed black; background: limegreen; padding: 25px; margin: 25px 0; display: none; position">
      ? Drop files here!
    </div>
    ? hover files here

    【讨论】:

    • 这在 Safari 5、Chrome 22 和 FF 15 中完美运行。谢谢! PS if/三元条件很巧妙。
    • 对 IE10 有什么建议吗?
    • Firefox 现在除了浏览器特定的之外还包含Files,但存储在具有数字索引的对象中,而 Chrome 是一个普通数组。
    • @bouke,您的代码帮了大忙!谢谢!如果您需要让代码在 IE10/IE11 上运行,请使用:dt.types != null &amp;&amp; ((dt.types.length &amp;&amp; dt.types[0] === 'Files') || dt.types.contains('application/x-moz-file')) 作为显示 dropzone 的条件。
    • 为什么不直接做if(dt.types &amp;&amp; (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files')))。这似乎适用于所有浏览器
    【解决方案2】:

    进一步完善bouke的回答:

    由于 chrome 在每个元素的每个 Dragenter 上调用文档的 dragleave,它可能会导致 dropzone 闪烁,尤其是在嵌套元素很多的情况下。

    $(document).on('dragleave', function(e) {
        dragTimer = window.setTimeout(function() {
            $("#dropzone").hide();
            }, 25);
    });
    

    我为解决这个问题所做的就是稍微增加超时并在设置每个超时之前添加 clearTimeout,因为以前在某些情况下会有多个超时在 dragover 事件中未清除,因为 dragTimer 存储只有最新的。结果版本:

    $(document).on('dragleave', function(e) {
        window.clearTimeout(dragTimer);
        dragTimer = window.setTimeout(function() {
            $("#dropzone").hide();
        }, 85);
    });
    

    顺便说一句,谢谢你的想法!我的另一个解决方案是绝对痛苦:)

    【讨论】:

    • 有一个更好的方法来实现这一点:每次输入嵌套元素时都会调用ondragstart,这样您就可以保留一个引用计数器。在这里找到它:stackoverflow.com/a/21002544/8277225
    【解决方案3】:

    我只是用它来检测dragover事件中的文件:

    Array.prototype.indexOf.call(files, "Files")!=-1 // true if files
    

    【讨论】:

      【解决方案4】:

      使用下面的函数检查拖拽源是否为外部文件。

      在 Windows 7 上测试:

      • 火狐39版
      • Chrome 版本 44
      • Safari 版本 5.1.7
      function isDragSourceExternalFile(dataTransfer){
          // Source detection for Safari v5.1.7 on Windows.
          if (typeof Clipboard != 'undefined') {
              if (dataTransfer.constructor == Clipboard) {
                  if (dataTransfer.files.length > 0)
                      return true;
                  else
                      return false;
              }
          }
      
          // Source detection for Firefox on Windows.
          if (typeof DOMStringList != 'undefined'){
              var DragDataType = dataTransfer.types;
              if (DragDataType.constructor == DOMStringList){
                  if (DragDataType.contains('Files'))
                      return true;
                  else
                      return false;
              }
          }
      
          // Source detection for Chrome on Windows.
          if (typeof Array != 'undefined'){
              var DragDataType = dataTransfer.types;
              if (DragDataType.constructor == Array){
                  if (DragDataType.indexOf('Files') != -1)
                      return true;
                  else
                      return false;
              }
          }
      }
      

      使用 JQuery 的示例用法

      $(document).on('dragover', function(e){
          var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
          console.log(IsFile);
      });
      

      【讨论】:

        猜你喜欢
        • 2011-03-26
        • 1970-01-01
        • 1970-01-01
        • 2015-09-26
        • 1970-01-01
        • 2020-08-06
        • 1970-01-01
        • 1970-01-01
        • 2013-06-07
        相关资源
        最近更新 更多