角度材质不适用于角度元素

问题描述 投票:0回答:2

我正在尝试使用角度材质创建一组角度元素。当我运行 Angular 应用程序时,一切正常。然而,一旦我导出我的元素,使用 Angular Material 的东西就会崩溃。

这就是我的组件中的内容

<div fxLayout="row" fxLayoutGap="15px">

  <mat-form-field appearance="outline">
    <mat-label>First Name</mat-label>
    <input matInput type="text" />
  </mat-form-field>

  <mat-form-field appearance="outline">
    <mat-label>Last Name</mat-label>
    <input matInput type="text" />
  </mat-form-field>

</div>

<button mat-raised-button color="primary">Submit</button>

当我在 Angular 项目中运行它时,它看起来就像我预期的那样(注意:为了运行它,我用我的测试元素标签替换了 Angular 项目中的 index.html 主体)

Angular 项目中运行的 Angular 元素的屏幕截图

然后我尝试使用 Angular 元素导出它。我运行

ng add @angular/elements
并将以下内容添加到我的 app.module.ts

@NgModule({
  declarations: [
    AppComponentTestElementComponent,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatInputModule,
    FlexLayoutModule,
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  providers: [],
  // bootstrap: [AppComponent],
})
export class AppModule {
  constructor(private injector: Injector) {}

  ngDoBootstrap() {
    const elements = [
      { name: 'test-element', component: TestElementComponent },
    ];

    // I plan on adding a bunch of elements which I why I have the for loop
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];

      const ngElement = createCustomElement(element.component, {
        injector: this.injector,
      });
      customElements.define(element.name, ngElement);
    }
  }
}

我会注意到,我也尝试将其移至

platformBrowserDynamic().bootstrapModule(AppModule)
的 .then 中的 main.ts 文件,并且得到了相同的结果。

然后我也有 concat 脚本

const fs = require("fs-extra");
const concat = require("concat");

(async function () {
  const files = [
    "./dist/elements-demo/runtime.js",
    "./dist/elements-demo/main.js",
    "./dist/elements-demo/polyfills.js",
  ];

  await fs.ensureDir("elements");
  await concat(files, "elements/elements.js");
  await fs.copyFile("./dist/elements-demo/styles.css", "elements/styles.css");
})();

然后我有 build:elements 脚本

ng build --output-hashing none && node concat.js

所以我创建了一个纯 HTML 页面并尝试使用该元素

<!DOCTYPE html>
<html>
  <title>Elements Demo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link
    href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"
    rel="stylesheet"
  />
  <link
    href="https://fonts.googleapis.com/icon?family=Material+Icons"
    rel="stylesheet"
  />

  <body>
    <h1>Customer's Website</h1>

    <test-element></test-element>

    <script src="http://localhost:8080/elements/elements.js"></script>
  </body>
</html>

这基本上给了我一个完全空白的页面: 在非角度 HTML 页面中使用元素后不起作用

我也尝试过包括

<link href="http://localhost:8080/elements/styles.css" rel="stylesheet" />
,但这不起作用。我尝试过使用
<link href="https://unpkg.com/@angular/[email protected]/prebuilt-themes/indigo-pink.css" rel="stylesheet"/>
但没有任何变化。

这是我正在使用的所有东西的版本

  "dependencies": {
    "@angular/animations": "~12.2.0",
    "@angular/cdk": "^12.2.12",
    "@angular/common": "~12.2.0",
    "@angular/compiler": "~12.2.0",
    "@angular/core": "~12.2.0",
    "@angular/elements": "^12.2.13",
    "@angular/flex-layout": "^12.0.0-beta.35",
    "@angular/forms": "~12.2.0",
    "@angular/material": "^12.2.12",
    "@angular/platform-browser": "~12.2.0",
    "@angular/platform-browser-dynamic": "~12.2.0",
    "@angular/router": "~12.2.0",
    "concat": "^1.0.3",
    "document-register-element": "^1.7.2",
    "rxjs": "~6.6.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4"
  },

编辑

我尝试使用 ShadowDOM 进行视图封装,并且确实有效。

使用 Shadow DOM 导出

我尝试了使用 Shadow DOM 进行视图封装的所有组合,但上面的屏幕截图是我每次都得到的。

javascript html angular angular-material angular-elements
2个回答
0
投票

在 Angular 15 中,当组件的封装设置为 Viewencapsulation.Emulate 时,图标会显示在父页面上包含的字体库中。


0
投票

我对基于角度元素的微前端也遇到了类似的问题,并在根组件中设置了

ViewEncapsulation.ShadowDom
。角度材质组件未设计样式。

为什么不起作用
我对代码的深入研究表明

  • 在运行时,使用的材质主题将作为标签添加到影子根目录中
  • 在预构建的主题中,组件样式的变量是为 DOM 的
    <html>
    元素定义的。在普通的 SPA 中,所有内容都位于 html 元素内,因此所有内容都可以访问这些变量

由于shadow DOM是主机页面的CSS和微前端/Web组件的CSS之间的边界,因此shadow-root内部的所有内容都无法访问shadow-root外部的CSS(为标签中的标签定义一些内容)影子根内的标签不起作用)。

我的解决方案
我在应用程序的根组件中添加了一个 div,它包含了所有内容。

<div id="mfe-container">
   ...everything that was in the app.component.html before...
</div>

我没有将主题包含在

html
元素中,而是将其包含在 styles.scss 的包装元素中

@use '@angular/material' as mat;

// my custom theme file
@use './m3-theme';

// The core mixin must be included exactly once for your application, even if you define multiple themes. 
// Including the core mixin multiple times will result in duplicate CSS in your application.
// https://material.angular.io/guide/theming#the-core-mixin
@include mat.core();

#mfe-container {
  @include mat.all-component-themes(m3-theme.$light-theme);
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.