Html2canvas: DOMException:无法在“ShadowRoot”上设置“adoptedStyleSheets”属性:不允许在多个文档中共享构造的样式表

创建于 2019-11-04  ·  13评论  ·  资料来源: niklasvh/html2canvas

DOMException:无法在“ShadowRoot”上设置“adoptedStyleSheets”属性:不允许在多个文档中共享构造的样式表

最有用的评论

在 angular 8 和 ionic 4 中使用相同的问题

所有13条评论

我也有同样的问题; 怎么处理呢?

在 angular 8 和 ionic 4 中使用相同的问题

同样的问题ionic4,如何解决?

我正面临着与 ionic 5 相同的问题......有人找到了任何解决方案吗?

离子4中宇鹏的临时计划

  • 索引.html
<body>
  <div id="html2canvas"></div>
  <app-root></app-root>
</body>
  • xxx.ts
const element = document.getElementById('html2canvas');
const targetElement = document.getElementById('target').cloneNode(true);
element.appendChild(targetElement);
this.html2canvas.html2canvas(element.firstChild).then((img) => {
    this.img = img;
    element.firstChild.remove();
}).catch((res) => {
    console.log(res);
});
  • Html2canvasService.service.ts
import {Injectable} from '@angular/core';
import {AlertService} from './alert.service';

declare let html2canvas;

@Injectable()
export class Html2canvasService {
    constructor(private alert: AlertService) {

    }

    public html2canvas(ele) {

        if (!ele) {
            return;
        }

        const option = {allowTaint: true, useCORS: true};
        return html2canvas(ele, option).then((canvas) => {
            if (canvas) {
                return canvas.toDataURL('image/png');
            }
            return null;
        }).catch((res) => {
            console.log(res);
            return res;
        });
    }
}

@G-yanpeng 你能详细说明一下你的解决方案吗? 我正在尝试对 ionic 4 angular8 版本做同样的事情。

谢谢!

同样的问题。 有人找到任何解决方案吗?

谢谢!

@G-yanpeng Can you please elaborate more your solution? Im trying do the same for ionic 4 angular8 version.

Thank you!

angular8 有了新的变更,导致 html2canvas 不能正常工作。那么就有了这个临时解决方案,让 html2canvas 在 angular 之外工作,将需要生成图片的 dom 拷贝到 angular 入口(app-root)的同层来避免angular造成的影响。

Angular8 has new changes that cause html2canvas to not work properly. Then there is this temporary solution to make html2canvas work outside of angular, copy the dom that needs to generate the image to the same layer of the angular entry (app-root) to avoid the impact of angular.
-- by google translate

image

您能否提供xxx.ts组件文件的完整代码? 尝试导出到.pdf时,我们也遇到相同的错误。 除此错误外,其他一切都正常。 我也可以查看.pdf文件。
这是我的代码:
(Translated to Chinese using Google translator)
`
import { Component, OnInit } from '@angular/core';
import { WcExpenditureCalcPipe } from 'src/app/_pipes/wc-expenditure-calc.pipe';
// export to pdf
import { Router } from '@angular/router';
import { ExportAsService, ExportAsConfig } from 'ngx-export-as';
import { Platform } from '@ionic/angular';
import { FileOpener } from '@ionic-native/file-opener/ngx';
import { File } from '@ionic-native/file/ngx';
import { FileTransfer, FileTransferObject } from '@ionic-native/file-transfer/ngx';

  @Component({
    selector: 'app-wc-estimate',
    templateUrl: './wc-estimate.page.html',
    styleUrls: ['./wc-estimate.page.scss'],
    providers: [WcExpenditureCalcPipe]
  })
  export class WcEstimatePage implements OnInit {
    dataEntered: any;
    wcEstimate: any;

    // export config
    storageDirectory: any;

    exportAsConfig: ExportAsConfig = {
      type: 'pdf', // the type you want to download
      elementId: 'myDiv', // the id of html/table element
      options: {
        margin: 15,
        jsPDF: {
          orientation: 'portrait',
          format: 'a4',
          unit: 'mm'
        },
        pdfCallbackFn: this.pdfCallbackFn // to add header and footer
      },
    }
    constructor(
      public router: Router,
      private exportAsService: ExportAsService,
      private transfer: FileTransfer,
      private file: File,
      private platform: Platform,
      private fileOpener: FileOpener,
      private wcExpenditureCalcPipe: WcExpenditureCalcPipe
    ) {
      this.platform.ready().then(() => {
        if (!this.platform.is('cordova')) {
          return false;
        }

        if (this.platform.is('ios')) {
          this.storageDirectory = this.file.externalDataDirectory;
        }
        else if (this.platform.is('android')) {
          this.storageDirectory = this.file.externalDataDirectory;
        }
        else {
          return false;
        }
      });
    }

    ngOnInit() {
      this.dataEntered = JSON.parse(localStorage.getItem('DataEntered'));
      this.getValues(this.dataEntered);
    }
    getValues(dataEntered: any) {
      this.wcEstimate = this.wcExpenditureCalcPipe.getWCE(dataEntered)
      console.log(this.wcEstimate);
    }

    // export PDF
    export(event) {
      const fileTransfer: FileTransferObject = this.transfer.create();

      this.exportAsService.get(this.exportAsConfig).subscribe((data: any) => {
        const fileName = 'PReport ' + this.dataEntered.Project_Name + ' - WC Estimate.pdf';
        fileTransfer.download(data, this.storageDirectory + fileName).then((entry) => {
          this.fileOpener.open(entry.toURL(), 'application/pdf').then(() => {
          }).catch(e => {
            console.log('Error opening file', e);
          });
        }, (error) => {
          console.log('error ' + JSON.stringify(error));
        });
      });
      event.preventDefault();
    }
    pdfCallbackFn(pdf: any) {
      // example to add page number as footer to every page of pdf
      const noOfPages = pdf.internal.getNumberOfPages();
      for (let i = 1; i <= noOfPages; i++) {
        pdf.setPage(i);
        pdf.text('WC Estimate', 15, 10)
        pdf.text('Page ' + i + ' of ' + noOfPages, 15, pdf.internal.pageSize.getHeight() - 10);
      }
    }

    //Edit report 
    editClick(event: any) {
      localStorage.setItem('isEdit', 'true');
      this.router.navigateByUrl('/dashboard/landing');

    }
    //done click 
    doneClick(event: any) {
      this.router.navigateByUrl('/dashboard/review');

    }
    // exit click 
    exitClick(event: any) {
      this.router.navigateByUrl('/dashboard/entry-point');
    }

  }

`
The platform.ready event is really not required. I was trying to add to 'Download' folder if it is android and 'Documents' folder if it is iOS.

@ravimallya
我更新了 html2canvasservice.service.ts 中的内容,但我认为它不会帮助你。 需要注意的是,使用这个临时方案,可以正常生成图片,但是还是会报throw异常。
也许您可以尝试使用 JSPDF 和 html2canvas 生成 PDF。

离子4中宇鹏的临时计划

  • 索引.html
<body>
  <div id="html2canvas"></div>
  <app-root></app-root>
</body>
  • xxx.ts
const element = document.getElementById('html2canvas');
const targetElement = document.getElementById('target').cloneNode(true);
element.appendChild(targetElement);
this.html2canvas.html2canvas(element.firstChild).then((img) => {
    this.img = img;
    element.firstChild.remove();
}).catch((res) => {
    console.log(res);
});
  • Html2canvasService.service.ts
import {Injectable} from '@angular/core';
import {AlertService} from './alert.service';

declare let html2canvas;

@Injectable()
export class Html2canvasService {
    constructor(private alert: AlertService) {

    }

    public html2canvas(ele) {

        if (!ele) {
            return;
        }

        const option = {allowTaint: true, useCORS: true};
        return html2canvas(ele, option).then((canvas) => {
            if (canvas) {
                return canvas.toDataURL('image/png');
            }
            return null;
        }).catch((res) => {
            console.log(res);
            return res;
        });
    }
}

非常感谢! 很好的解决方法!

离子4中宇鹏的临时计划

  • 索引.html
<body>
  <div id="html2canvas"></div>
  <app-root></app-root>
</body>
  • xxx.ts
const element = document.getElementById('html2canvas');
const targetElement = document.getElementById('target').cloneNode(true);
element.appendChild(targetElement);
this.html2canvas.html2canvas(element.firstChild).then((img) => {
    this.img = img;
    element.firstChild.remove();
}).catch((res) => {
    console.log(res);
});
  • Html2canvasService.service.ts
import {Injectable} from '@angular/core';
import {AlertService} from './alert.service';

declare let html2canvas;

@Injectable()
export class Html2canvasService {
    constructor(private alert: AlertService) {

    }

    public html2canvas(ele) {

        if (!ele) {
            return;
        }

        const option = {allowTaint: true, useCORS: true};
        return html2canvas(ele, option).then((canvas) => {
            if (canvas) {
                return canvas.toDataURL('image/png');
            }
            return null;
        }).catch((res) => {
            console.log(res);
            return res;
        });
    }
}

我在服务的以下函数调用中收到以下错误:“错误类型错误:html2canvas 不是函数”:

return html2canvas(ele, option).then((canvas) => {
    if (canvas) {
        return canvas.toDataURL('image/png');
    }
    return null;
})

离子4中宇鹏的临时计划

  • 索引.html
<body>
  <div id="html2canvas"></div>
  <app-root></app-root>
</body>
  • xxx.ts
const element = document.getElementById('html2canvas');
const targetElement = document.getElementById('target').cloneNode(true);
element.appendChild(targetElement);
this.html2canvas.html2canvas(element.firstChild).then((img) => {
    this.img = img;
    element.firstChild.remove();
}).catch((res) => {
    console.log(res);
});
  • Html2canvasService.service.ts
import {Injectable} from '@angular/core';
import {AlertService} from './alert.service';

declare let html2canvas;

@Injectable()
export class Html2canvasService {
    constructor(private alert: AlertService) {

    }

    public html2canvas(ele) {

        if (!ele) {
            return;
        }

        const option = {allowTaint: true, useCORS: true};
        return html2canvas(ele, option).then((canvas) => {
            if (canvas) {
                return canvas.toDataURL('image/png');
            }
            return null;
        }).catch((res) => {
            console.log(res);
            return res;
        });
    }
}

这很好用。 非常感谢您的解决方案。 使用离子原生元素(如要复制的元素内的离子文本、离子图标),这是行不通的。 但是我将离子元素更改为 html。 现在它工作完美。

此页面是否有帮助?
0 / 5 - 0 等级