使用自己的CSS Angular在服务中加载HTML页面 [英] Load HTML page in a service with its own CSS Angular

查看:79
本文介绍了使用自己的CSS Angular在服务中加载HTML页面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个已添加到应用程序中的服务 PrintService .该服务从页面中提取元素,并使用提取的元素的内容呈现另一个窗口.

I have a Service, PrintService that I have added to my application. The Service extracts elements from a page and renders another window with the contents of the extracted elements.

import {Injectable} from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class PrintService {
  popupPrint(selector: string) {
    const printContents = (document.querySelector(selector) as HTMLTableElement).innerHTML;
    const popupWin = window.open('', '_blank', 'top=0,left=0,height=auto,width=auto');
    popupWin?.document.open();
    popupWin?.document.write(`
      <html>
        <head>
          <title>Print tab</title>
          <style>
            .d-flex  {
              width: 100%;
              display: flex;
              justify-content: space-between;
            }
            
             // ... More CSS

            @media print {
              .d-print-none {
                display: none;
              }
            }
          </style>
        </head>
        <body>
          <section class='d-print-none'>
            <button onclick="window.print();">Print</button>
            <button onclick="window.close();">Cancel</button>
          </section>
            ${printContents}
        </body>
        <script>
        (function() {
           window.print();
        })();
        </script>
      </html>`
    );
  }

  constructor() {
  }
}

这有效. Stackblitz上的打印服务

我现在的问题是这个,我需要将上述服务中的css样式删除到其自己的文件中,我该如何实现这一点

My Problem now is this, I need to be remove the css styles from the service above to its own file, How can I be able to achieve this

我最初的计划是将其移至文本文件并从角度读取文本文件,但我相信有更好的方法

My initial plan was to move it to a text file and read the text file from angular but I believe there is a better approach

为什么需要在单独的样式表中使用它?

我正在使用 bootstrap css在深色主题上构建应用程序.我需要提取表格并将其打印在明亮的主题上.我认为用户更喜欢在白色背景上打印黑色文本.

I am building an application on a dark theme using bootstrap css. I need to extract the table and print it on a light theme. I think users would prefer to print a black text on white background.

我有一个 PrintComponent


@Component({
  selector: 'app-print',
  templateUrl: './print.component.html',
  styleUrls: ['./print.component.less']
})
export class PrintComponent {

  @Input() selector: string;

  constructor(private printService: PrintService) {
  }

  print(): void {
    this.printService.popupPrint(this.selector);
  }

HTML只是一个按钮

And Html is just a button

<button class="btn btn-secondary btn-sm" (click)='print()' type="button">
  Print <span class="icon-print"></span>
</button>

这个想法是一种简单的方法来在页面上打印任何项目,例如我可以拥有的

The Idea is to a simple way to print any item on a page e.g I can have

<app-print selector='#reportTable'>
<table id='reportTable'>
  <!-- Contents of this table will be extracted and displayed for printing -->
</table>

我认为什么是更好的方法?

  • 当前,我的 PrintService 是一个大文件.将其提取到另一个文件中至少可以解决此问题.

  • Currently, my PrintService is a large file. Extracting it to a different file will at least solve this problem.

下一步如果可以将文件添加到缩小过程中,那就太好了

Next If the file can be added to the minification process, that would be great

我还希望有一种仅在需要时才延迟加载"此服务的方法

I also hope of a way to 'lazy load' this service only when required

如果可以的话,我可以简单地链接到此样式表吗?类似于< link rel ="stylesheet"href ="some/print/style.css"></link>

If possible, can I simply have a link to this stylesheet? something like <link rel="stylesheet" href="some/print/style.css"></link>

推荐答案

这是满足您所有期望甚至更多期望的一种方法.

Here's one way to cover all of your expectations and even a bit more.

重要提示:根据Angular/TypeScript配置的不同,某些操作可能必须稍有不同.这是针对带有SCSS的Angular 10.

Important: some things might have to be done slightly differently, depending on your Angular/TypeScript configuration. This is for Angular 10 with SCSS.

在以下位置创建 app/print/print-page.html :

<html>
    <head>
        <title>Print tab</title>
        <link rel="stylesheet" href="/print-styles.css" />
    </head>
    <body>
        <section class="d-print-none">
            <button onclick="window.print();">Print</button>
            <button onclick="window.close();">Cancel</button>
        </section>
        {{printContents}}
    </body>
    <script>
        (function () {
            window.print();
        })();
    </script>
</html>

请注意:

  • 我们正在将/print-styles.css 加载到< head> 中-我们将创建此文件并指示Angular稍后对其进行正确捆绑;
  • 有一个令牌 {{printContents}} ,我们将使用该令牌将自定义HTML注入页面.
  • we are loading /print-styles.css in the <head> - we will create this file and instruct Angular to properly bundle it later;
  • there's a token {{printContents}}, which we will use to inject custom HTML into the page.

我们将希望将此HTML文件导入到我们的 print.service.ts 文件中.为了做到这一点,TypeScript需要了解 .html 文件所保存的数据类型.这是通过键入文件( .d.ts )完成的.创建具有以下内容的文件 html.d.ts :

We will want to import this HTML file into our print.service.ts file. To be able to do this, TypeScript needs to understand what kind of data .html files hold. This is done via a typing file (.d.ts). Create a file html.d.ts with this content:

declare module '*.html' {
  const content: string;
  export default content;
}

默认情况下,TypeScript将能够在源代码中的任何地方找到类型声明,因此可以将该文件放置在源代码目录中的任何位置,例如 app/print/html.d.ts .

By default, TypeScript will be able to find type declarations anywhere in your source, so place this file wherever you feel like in your source code directory, e.g. app/print/html.d.ts.

默认情况下,Angular应用程序知道如何导入各种脚本/样式文件.但是,它不知道如何处理HTML文件.通过使用 raw-loader ,我们将指示Webpack将目标文件作为简单字符串导入,而无需进行任何转换.

By default an Angular application knows how to import various script/style files. It does not know how to treat HTML files, however. By using a raw-loader we will instruct Webpack to import the target file as a simple string without any transformations.

首先,您需要安装 raw-loader 依赖项:

First you need to install the raw-loader dependency:

npm i -D raw-loader

然后您可以:

  • 在应用程序配置级别配置Angular加载程序,以对所有以 .html 结尾的文件使用 raw-loader (可以使用来自 @ angular-builders/custom-webpack ,并且不在此问题范围之内);
  • 就地使用加载程序,这对于这样的一次性实例很好,这就是我们要做的事情.
  • configure Angular loaders at the application config level to use raw-loader for all files with names ending in .html (this can be done using a custom Webpack builder from @angular-builders/custom-webpack and is out-of-scope for this question);
  • use the loader in-place, which is fine for a one-off instance like this and is what we're going to do.

现在TypeScript知道如何解释HTML文件,我们可以将其导入到打印服务中,从而将演示文稿与服务完全分开.在 app/print/print.service.ts 中:

Now that TypeScript knows how to interpret the HTML file, we can import it into the print service, thus entirely separating the presentation from the service. In app/print/print.service.ts:

import { Injectable } from '@angular/core';

import printPageHTML from '!!raw-loader!./print-page.html';

@Injectable({
  providedIn: 'root',
})
export class PrintService {
  popupPrint(selector: string) {
    const printContents = document.querySelector(selector).innerHTML;
    const popupWin = window.open('', '_blank', 'top=0,left=0,height=auto,width=auto');
    popupWin.document.open();
    popupWin.document.write(printPageHTML.replace('{{printContents}}', printContents));
  }
}

在这里注意:

  • 我们如何为打印窗口导入基本HTML-从'!! raw-loader!./print-page.html';
  • 导入printPageHTML
  • 我们如何使用令牌替换注入要打印的任何HTML- printPageHTML.replace('{{printContents}}',printContents).

创建一个 app/print/print-styles.scss 文件,然后在其中定义所需的样式.您也可以在此处导入Bootstrap.

Create a app/print/print-styles.scss file and define your desired styles there. You may import Bootstrap here as well.

.d-flex  {
  width: 100%;
  display: flex;
  justify-content: space-between;
}

// ... More CSS

@media print {
  .d-print-none {
    display: none;
  }
}

6.捆绑CSS文件

我们需要指示Angular正确捆绑 print-styles.scss ,以便:

  • 此CSS默认在加载时未包含在应用程序中(我们希望打印窗口在以后延迟加载);
  • 该文件将被缩小并以可预测的名称包含在构建中(以便我们知道如何加载它-调用步骤1).

angular.json (又名工作区配置)中,修改 architect.build.options.styles 路径以包括样式文件,如下所示:

In angular.json (a.k.a. the workspace config) modify the architect.build.options.styles path to include the styles file, something like this:

"styles": [
  "src/styles/styles.scss",
  {
    "input": "src/styles/print-styles.scss",
    "inject": false,
    "bundleName": "print-styles"
  },
  ... other styles here
]

注意 inject bundleName -都很重要.

我在此处创建了一个示例存储库: https://github.com/juona/angular-打印演示.不幸的是,我无法在StackBlitz上运行它,因此最好克隆存储库并在您的计算机上尝试.

I have created a demo repo here: https://github.com/juona/angular-printing-demo. Unfortunately, I was not able to run this on StackBlitz, so better clone the repo and try it on your machine.

  • 步骤1-3是可选步骤,但我认为将HTML与服务分离也是一个好主意.

  • Steps 1-3 are optional, but I thought that it would be a good idea to separate the HTML from the service too.

如果要在开发模式下进行测试,则还需要使用 extractCss 选项.默认情况下,仅对生产版本启用此选项.要在开发人员模式下将其打开,请在 architect.build.options 中添加"extractCss":true .如果您不这样做,则 print-styles.scss 将被捆绑到 print-styles.js (JavaScript!)文件中-这不是我们想要的.

If you wish to test this in development mode, you need to also use the extractCss option. This option is enabled by default only for production builds. To turn it on in dev mode, add "extractCss": true to architect.build.options. If you don't do this, print-styles.scss will be bundled into a print-styles.js (JavaScript!) file - this is not what we want.

这不是一个非常灵活的解决方案,因为您必须对CSS文件的名称进行硬编码,必须使用 extractCss 标志,使用JavaScript不方便,因为您必须编写放在 script 标记内,依此类推.但这确实可以实现您想要的功能.

This is not a very flexible solution because you have to hard-code the name of the CSS file, you must use the extractCss flag, using JavaScript is inconvenient as you have to write it inside the script tag and so on. But it does seem to achieve exactly what you were looking for.

这里有一些可供选择的调查方式,以防万一,因为我懒得自己做:

Here are some alternatives to investigate, just in case, as I'm too lazy to do that myself:

  • Angular提供了一种本机解决方案,可以在单独的选项卡中打开组件-我相信可以利用这一点,尤其是在需要更多涉及打印页面准备的情况下.

  • Angular offers a native solution to open components in separate tabs - I am sure that this could be utilised, especially if more involved print page preparation is required.

您还可以尝试使用CSS的 all:unset 取消设置应用于组件及其子组件的任何样式,同时还在打印过程中隐藏所有不相关的组件.这样一来,您就可以避免使用新的窗口/标签,同时还具有覆盖全局CSS(引导程序)的功能.

You may also try to use CSS's all: unset to unset any styles applied to a component and its children, whilst also hiding any unrelated component while printing is in progress. This would allow you to avoid using new windows/tabs while giving the ability to override global CSS (Bootstrap).

这篇关于使用自己的CSS Angular在服务中加载HTML页面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆