如何从 Angular 2 onDrop 事件中获取文件?

Posted

技术标签:

【中文标题】如何从 Angular 2 onDrop 事件中获取文件?【英文标题】:How to get files from angular 2 onDrop event? 【发布时间】:2017-08-16 16:02:32 【问题描述】:

我试过这样,但onDrop 方法在我放到它时不返回图像文件...

onDragStart(event, data: any) 
  event.dataTransfer.setData('data', data);

onDrop(event, data: any) 
  let dataTransfer = event.dataTransfer.getData('data');
  event.preventDefault();

allowDrop(event) 
  event.preventDefault();

<div (drop)="onDrop($event, dropData)" (dragover)="allowDrop($event)"></div>
<div (dragstart)="onDragStart($event, dragData)"></div>

有什么解决办法吗?

【问题讨论】:

为什么要阻止事件的默认行为? 如果不阻止,拖放将不起作用... 【参考方案1】:

onDrop 事件仅在 onDragOver 有 preventDefault()stopPropagation() 方法在事件上运行时触发。

HTML

<div
    (drop)="onDrop($event)"
    (dragover)="onDragOver($event)"
>
    Drop target
</div>

DropComponent.ts

export class DropComponent 
    onDrop(event) 
        event.preventDefault();
    
    onDragOver(event) 
        event.stopPropagation();
        event.preventDefault();
    

更新

这是必需的,因为默认情况下,浏览器会在拖放到 html 元素时阻止任何事情发生。更多信息请访问 MDN - Defining a valid drop zone

【讨论】:

如果你能解释为什么会这样就太好了。【参考方案2】:

下面是 Angular 2/4/6 中拖放的完整代码:

drag.component.ts:

import  Component  from '@angular/core';

@Component(
  selector: 'drag-root',
  templateUrl: './drag.component.html',
  styleUrls: ['./drag.component.css']
)
export class AppComponent 

  allowDrop(ev) 
    ev.preventDefault();
  

  drag(ev) 
    ev.dataTransfer.setData("text", ev.target.id);
  

  drop(ev) 
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text");
    ev.target.appendChild(document.getElementById(data));
  

拖动.component.html:

<h2>Drag and Drop</h2>
<div  id="div1" 
      (drop)="drop($event)" 
      (dragover)="allowDrop($event)">

      <img 
      src="https://images.pexels.com/photos/658687/pexels-photo-658687.jpeg?auto=compress&cs=tinysrgb&h=350" 
      draggable="true" 
      (dragstart)="drag($event)" 
      id="drag1"
       
      >
</div>

<div id="div2" 
  (drop)="drop($event)" 
  (dragover)="allowDrop($event)">
</div>

drag.component.css:

#div1, #div2 
    float: left;
    width: 100px;
    height: 35px;
    margin: 10px;
    padding: 10px;
    border: 1px solid black;

快照:

【讨论】:

它对我有用,但为了从 div 获取数据,我使用了下面的代码,它给出了文件 Object, var data = event.dataTransfer.files[0];【参考方案3】:

您可以将 onDrop 功能包装到可重用指令中。像这样:

https://gist.github.com/darrenmothersele/7afda13d858a156ce571510dd78b7624

将此指令应用于元素:

<div (appDropZone)="onDrop($event)"></div>

该事件由已删除文件的 javascript 数组触发。因此,您在组件中的 onDrop 实现如下所示:

onDrop(files: FileList) 
  console.log( files );

【讨论】:

【参考方案4】:

正如其他人所说,您需要在 (dragover) 事件上调用 event.preventDefault()event.stopPropagation() 以使您的容器成为有效的放置区。

我编写了一个高度可定制的 Angular 组件,它实现了正确的 Drag'n'Drop 行为,因此我不需要一遍又一遍地复制它,它会返回一个已删除文件的列表作为输出事件。 这可以找到here。

导入模块后,您可以访问组件:

<ngx-dropzone [multiple]="false" [maxFileSize]="2000"></ngx-dropzone>

您可以设置一些选项,它带有一个不错的默认样式(可以在 GitHub 存储库中找到屏幕截图)。如果您愿意,您甚至可以使用您自己的 div 容器和您的自定义样式和悬停效果,并将其放入 dropzone。可以在 API 描述中找到这方面的详细信息。

<ngx-dropzone [customContent]="customDropzone" (filesAdded)="onFilesDropped($event)">
<ng-template #customDropzone>
    <div class="custom-dropzone">
        This is my custom content
    </div>
</ng-template>

【讨论】:

我为此花了一整天的时间,但您的组件在 3 分钟内完成。我有一个问题,我们可以在同一个保管箱中显示上传的图像吗? @KishanOza 目前尚未实现,但我在 GitHub 上也收到了很多请求。我将尝试在接下来的几周内添加图像预览。我建议您“观看”存储库,以便了解更新。 是的,我设法通过在数组中添加图像并分别显示它们来做到这一点。但如果我们可以在 self @PeterFreeman 的下拉框中显示相同的图像,那就太好了 现在可以使用最新版本。 :) 是的,这很酷..但它一次只显示一个图像..如果我删除新图像,​​它将覆盖前一个图像:(任何解决方案?并且没有删除该图像的选项:( 我正在创建类似 playstore 和 appstore 上传的 UI,用户可以在其中添加屏幕截图【参考方案5】:

您可以尝试使用Hostlistener 装饰器进行拖动事件,您可以看到它已实现,例如here in ng2-file-upload

【讨论】:

Hostlistener 将如何提供帮助? 我尝试添加@HostListener('drop', ['$event']),但它仍然返回空事件...【参考方案6】:

一个非常简单的指令,允许您将文件放置在任何位置。

IE:

@Directive(
  selector: '[dropFileZone]'
)
export class DropFileZoneDirective 

  @Output() onDropFile = new EventEmitter<File>();
  constructor()  

  @HostListener('dragover', ['$event'])
  allowDrop(event) 
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';
  

  @HostListener('drop', ['$event'])
  async onDrop(event) 
    event.stopPropagation();
    event.preventDefault();
    let fileList = event.dataTransfer.files; // Array of all files
    const fileExists: boolean = fileList.length > 0;
    if (!fileExists) 
      return;
    
    this.onDropFile.emit(fileList[0]);
  

在 .html 文件上使用它的方式:

<div dropFileZone (onDropFile)="handleDroppedFile($event)"> </div>

【讨论】:

以上是关于如何从 Angular 2 onDrop 事件中获取文件?的主要内容,如果未能解决你的问题,请参考以下文章

Blazor - ondrop 事件不返回文件对象

实时拖放移动

如何从Angular 2中的子组件事件触发父组件中的本地引用?

H5 拖拽读取文件和文件夹

h5拖放

如何从 Ionic 5 中的@ionic/angular 错误修复成员事件