javascript – 在页面上拖放文件 – 缺少一致的解决方案

这是我正在努力实现的:

There are multiple dropzones on the page. Users should be able to drag
files from their OS and drop them into the dropzones.

Dropzones get highlighted during dragging. There are two visually different types
of highlighting: “Target” (for example, the element gets outlined with a dashed
border) and “Hover” (for example, the element gets a bright background).

The Target highlighting is applied/removed on/from all dropzones at
once:

  • When a user drags a file over the page, all dropzones should be highlighted with the Target highlighting.
  • When a user drags the file outside the page, or cancels the drag/drop operation, or performs the drop, then the Target
    highlighting should be removed from all the dropzones.

The Hover highlighting should be applied to only one dropzone:

  • When a user drags a file over a dropzone, that dropzone should be highlighted with the Hover highlighting.
  • When a user drags the file outside that dropzone, or cancels the drag/drop operation, or performs the drop, then the Target
    highlighting should be removed from the dropzone.

When a user drops a file on a dropzone, the file’s name should appear
inside the dropzone.

When a user drops a file on the page outside dropzones, all dropzones
highlighting should be removed and nothing else should happen.
Specifically, the dropped file should not be opened by the browser.

The solution should be as much graceful as possible: dirty hacks like using timeouts, counting dragenter/dragleave events and reapplying highlighting on every dragover are not welcome.

The solution should work in latest versions of major browsers.

这是我到目前为止达到的目标:attempt 1,attempt 2.

我已经成功解决的问题

>删除文件夹外的文件导致浏览器打开文件.

解:

$(document).on('dragover drop', function (e) {
    e.preventDefault();
});

>将文件删除到dropzone会生成一个drop事件,其目标等于dropzone的子进程,而不是dropzone本身.

解:

$dropzones.on( 'drop', function (event) {

  /* ... */

  // Find the dropzone responsible for the event
  $targetDropzone = $(event.target).closest($dropzones);

  /* ... */
});

>将文件悬停在dropzone的子节点上,会生成多个拖拽事件,使Hover高亮显示立即消失(当鼠标光标离开dropzone时,应从dropzone中删除Hover突出显示,因此它将绑定到dragleave事件).

解决方案:使用dragout事件而不是拖拽. dragout是由jquery.event.dragout插件提供的自定义事件.这个事件不会针对元素的孩子发射.

未解决的问题

>无法检测拖放文件离开文档或窗口的时刻,以便执行“删除目标高亮”命令.

自定义拖放插件被设计为仅适用于< body>的子项.它既不适用于文档也不适用于窗口.

官方的dragstart和dragend事件根本无法拖动文件.这是expected behavior. 🙁

绑定到文档的拖放和拖动事件不仅在鼠标指针进入/离开文档时也会在指针进入/离开文档的子级时触发.更糟糕的是,第一个$(document).on(‘dragenter’)事件的event.target可能会显示为一个元素(它可以是文档或其子节点),最后一个出现的是$(document).on(‘ dragleave’)可以显示为不同的元素,因此您无法通过比较event.targets来解决问题.

由于这些问题,我未能优雅地跟踪鼠标离开文档的时刻.

我试图使用旨在解决此问题的draghover插件.我设法使其工作(仅在Chrome中测试),但是在第一次成功下载之后它将停止正常工作.查看失败的尝试here.
>虽然不可能直观地说明,但是当文件悬停在文档上时,dragenter事件被多次触发.因此,突出显示应用多次而不是一次.
>拖动鼠标时,鼠标悬停在dropzones外面时,显示浏览器的标准“can not drop here”图标,当鼠标悬停在dropzones上时,可以显示“can drop here”图标.

UPD 2014-03-16 15:30,回复Ian Bytchek的回答

你好同志!感谢您的详细回复.不幸的是,您的解决方案有一些问题.

1.

  1. Unable to detect the moment when the dragged file leaves the document or window, so that a “remove Target highlighting” command could be executed.

  
  $(document).on(‘dragleave’,…必须做的伎俩,看下面的小提琴.

不,这是非常糟糕的.

假设您在< body>上聆听drag和dragleave事件.每当拖动鼠标指针悬停在任何元素的边缘时,两个事件将触发:

>在< body>上拖放将event.target设置为悬停元素;
>拖曳在< body>上将event.target设置为悬停元素的父项.

我认为目标突出显示将应用于.dropzone.target-higlighing选择器.通过使用.target-highlighting .dropzone选择器应用目标突出显示,您做了一个机智的技巧.

看看你的代码:

$('body')
    .on('dragenter', function (event) {
        $(event.target).addClass('target-highlighting');
        event.preventDefault();
    })
    .on('dragleave drop', function (event) {
        $(event.target).removeClass('target-highlighting-class');
        event.preventDefault();
    })

如果dropzone驻留在多个嵌套容器中,则拖动文件跨容器将导致目标突出显示类从最外层的容器迁移到最内层.由于您在CSS中使用了.target-highlighting .dropzone选择器,所以目标突出显示为…

…直到您将文件拖动到不是dropzone的父母之一的元素上.它可能是侧栏或dropzone本身.当这种情况发生时,.target-highlighting .dropzone选择器停止应用,目标突出显示消失.

这是不能接受的.目标突出显示应仅在文件拖动到页面上并在将文件拖出页面或拖动已完成(通过删除或取消)时将其移除时才会显示).

2.

  1. Though it’s impossible to tell visually, the dragenter event gets fired many times while the file hovers over the document. Thus,
    highlighting is applied multiple times instead of one.

  
  每次当鼠标进入某个元素时都会触发该事件.所以,
  当您拖动页面时,它会进入许多元素并触发许多元素
  倍.为了避免这种情况,您需要“禁用”每个下面的所有内容
  droparea,有两种方法可以做到这一点.
  
  首先是使用css指针事件,这是最优雅的,但是
  最不友好的浏览器它与最近的,和我一起工作
  亲爱的
  
  其次,是在droparea顶部创建一个透明的叠加层 –
  鼠标只会击中,而不是下面的元素,哪个
  将阻止多个拖动进入事件.

这些解决方案可以触发在鼠标指针位于dropzone内时应用的悬停突出显示. (BTW,我已经找到了一个更优雅的解决方案:一个dragout事件插件,请参见上面的“解决的问题”部分中的#3)

但是,当鼠标指针位于dropzone的内部和外部时,它们完全不适合应用于Target突出显示.您必须禁用整个页面的鼠标事件(使用指针事件:无;或覆盖)),并且dropzones将不再接受丢弃.

3.

  1. The mouse pointer during drag should display the browser’s standard “can’t drop here” icon
    when hovering outside dropzones and the “can drop here” icon when
    hovering over dropzones.

I’m not 100% certain on this, but on MAC I can’t seem to change the
icon while dragging, as it uses the special default one. I assume this
can’t be done, but would love to learn otherwise.

我已经注意到,我所问的已经在Chrome上工作了!请参阅下面的链接.

Firefox不会改变鼠标指针. 🙁

一个更好的样板测试解决方案

There are also some pretty good looking libraries, like 07006, which I don’t have experience with, yet they are a good source of “inspiration”.

我看过这个插件.它不能解决上述问题.目标突出显示不被应用,当您将文件拖动到dropzone时,悬停突出显示会闪烁.

另外,我不能使用它,因为我有我自己的dropzone实现.例如,我的dropzone允许用户对添加到dropzone的文件进行排序.我只需要一个解决方案来处理拖动事件.

My personal advice would be to use per-droparea plugin approach, not per-page approach as in your examples. Those components tend to grow pretty big once you add the uploading logic, validation, etc.

你是绝对正确的.在我的项目中,我使用了精彩的jQuery UI Widget Factory.这是一种定义jQuery插件的方法,它们的行为彼此分开.

在这里,我创建了一个更好的样板来测试更多的解决方案:http://jsbin.com/rupaloba/4/edit?html,css,js,output

我希望这不是太复杂.

Privet安德烈!我最近面临的大部分都是尝试分享知识.

1.无法检测拖动文件离开文档或窗口的时刻,以便执行“删除目标高亮”命令.

$(document).on(‘dragleave’,…必须做的伎俩,看下面的小提琴.

2.虽然不可能直观地说明,但是在文件悬停在文档上时,dragenter事件被多次触发.因此,突出显示应用多次而不是一次.

每次当鼠标进入某个元素时都会触发该事件.所以,当你拖动页面,它进入许多元素和火灾许多次.为了避免这种情况,您需要“禁用”每个droparea下面的所有内容,有两种方法可以执行此操作.

首先是使用css pointer events,这是最优雅但最不友好的浏览器解决方案.它与最近的工作,我个人喜欢它.

第二,是在droparea顶部创建一个透明的叠加层 – 鼠标只会击中,而不是下面的元素,这将阻止多个拖动输入事件.

鼠标指针在拖动时应该显示浏览器的标准“不能在这里”,当悬停在dropzones之外,当悬停在dropzones上时,可以显示“可以放在这里”图标.

我不是100%肯定这个,但在MAC我似乎不能改变图标拖动时,因为它使用特殊的默认.我认为这是不可能的,但是不妨学习.您可以使用不同的设计,如背景颜色更改,或者可能添加将跟随鼠标的游标状的div.该示例显示了背景的技巧.

示例:http://jsfiddle.net/ianbytchek/Q6uEp/8/

这涉及到这些问题.我的个人建议是使用每个Droparea插件方法,而不是按照你的例子中的每页方法.一旦你添加了上传逻辑,验证等,这些组件就会变得很大.简而言之:

>一个基本的jQuery插件扩展了两个(更多)组件所需的逻辑.
>它处理所有拖放业务共享基础css / html以保持一切都干.
> index.js $(document).on(‘dragenter dragover drop’)中的某个地方,功能…阻止在浏览器中打开文件并导航.

还有一些很漂亮的图书馆,如http://www.dropzonejs.com/,我没有经验,但它们是“灵感”的一个很好的来源.

我还在我的代码中使用了以下代码来掩盖旧版浏览器中的指针事件(但是从来没有测试过) – 它检查鼠标是否在元素的边界之外.

// jQuery event configuration.
jQuery.event.props.push('dataTransfer', 'pageX', 'pageY');

element.on('dragleave', function ( event) {                                                                                                                                        
    var elementPosition = element.offset();                                                                                                                                                 
    var elementWidth = element.width();                                                                                                                                                     
    var elementHeight = element.height();                                                                                                                                                   

    if (event.pageX < elementPosition.left || event.pageX > elementPosition.left + elementWidth || event.pageY < elementPosition.top || event.pageY > elementPosition.top + elementHeight) {
        element.removeClass(States.HIGHLIGHTED);                                                                                                                                            
    }       
    // …    
    // …    
    // …

更新1(2014-03-16 19:00)

@ Andrey’lolmaus’Mikhaylov,你是对的这些点 – 这是一个混乱,一旦你开始嵌套的东西.它进一步发挥它,原来是一个真正的贱人,所以我很感兴趣.我没有运气用拖拉机和拖拉机事件解决问题,但我确定解决方案存在.我没有想到的东西不太吸引人,但是:http://jsfiddle.net/ianbytchek/Q6uEp/14/

这是一个相当整洁的解决方案,我认为这将比你可以得到与其他apporaches更干净.同时,所有的坐标检查都感觉有点黑客.我很累的看着它,如果它被抛光到一个更好/更好的版本,这将是非常好的知道.

翻译自:https://stackoverflow.com/questions/22308882/drag-drop-files-on-the-page-lack-of-a-consistent-solution

转载注明原文:javascript – 在页面上拖放文件 – 缺少一致的解决方案