首页 > 解决方案 > Angular/Javascript - 下载文件链接在移动设备上不起作用

问题描述

我有一个 href 链接可以从我的应用程序中下载模板。它在 Chrome 和 IE 中运行良好,但在移动设备(Android 和 iPhone)中无法运行

我有这个函数,它通过点击链接被调用..

fileUrl: any;

getFileTemplate(): any {
    this.productService.getFile().subscribe((response) => {
      const fileContent = response;
      // An application or a document that must be opened in an application
      const blob = new Blob([fileContent], { type: 'application/octet-stream' });
      if (window.navigator.msSaveBlob) {
        // to download in IE
        window.navigator.msSaveBlob(blob, 'abcd.csv');
      } else {
        this.fileUrl= this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob));
        const a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);
        a.download = 'abcd.csv';
        a.click();
      }
    });
  }

并在 HTML 文件中

`<a href="javascript:void(null)"
   (click)="getFileTemplate();"
   id="link-inline-excel"
   class="u-text--document u-text--document-link"
   download="abcd.csv"><span>Title my file (7MB)</span></a>`

这不适用于移动设备。我在这里错过了什么吗?

标签: javascriptangularangular6mobile-devices

解决方案


你或多或少是在正确的轨道上。为了使您的代码正常工作,我可以提供的最小修改是在以下位置再添加一行getFileTemplate

getFileTemplate(): any {
  this.productService.getFile().subscribe((response) => {
    const fileContent = response;
    // An application or a document that must be opened in an application
    const blob = new Blob([fileContent], { type: 'application/octet-stream' });
    if (window.navigator.msSaveBlob) {
        // to download in IE
      window.navigator.msSaveBlob(blob, 'abcd.csv');
    } else {
      this.fileUrl= this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob));
      const a = document.createElement('a');
      a.href = window.URL.createObjectURL(blob);
      a.download = 'abcd.csv';

      document.body.appendChild(a); //<-- Need to add the link to the DOM

      a.click();
    }
  });
}

当然,虽然这可行,但它不是一个非常干净的解决方案。一方面,用户将能够看到新附加的链接。另一方面,Angular 文档建议避免直接 DOM 操作,Renderer2而是使用。

这是一个考虑到这两点的StackBlitz 示例

该示例创建了一个单独的Downloader组件,其作用类似于基本锚元素,但封装了触发下载的逻辑。然后,您可以在要触发文件下载的任何地方使用此组件。

答案的要点是这个片段:

...

constructor(
  private element: ElementRef,
  private renderer: Renderer2
) {}

...

download(data: Blob, filename: string) {
  if(!data) {
    return;
  }

  //Create the anchor element
  const link: any = this.renderer.createElement('a');

  //Create the URL
  const url: any = URL.createObjectURL(data);

  //Set the attributes for the anchor
  this.renderer.setProperty(link, 'href', url);
  this.renderer.setProperty(link, 'download', filename);

  //Ensure that the anchor will be hidden, both visibly and from screen readers
  this.renderer.setStyle(link, 'display', 'none');

  //Add the anchor element to the DOM
  this.renderer.appendChild(this.element.nativeElement, link);

  //Trigger click on the anchor element to trigger the download
  link.click();

  //Cleanup by removing the element and revoking the URL.
  this.renderer.removeChild(this.element.nativeElement, link);
  URL.revokeObjectURL(url);

  //Note: This is just a basic example, which does do DOM manipulation
  //on every download. You could, instead, append the element in OnInit,
  //adjusting its attributes when a download is triggered, and then
  //remove the element in OnDestroy.
}

推荐阅读