我正在尝试使用角度材质创建一组角度元素。当我运行 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: [
AppComponent,Ï
TestElementComponent,
],
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 进行视图封装的所有组合,但上面的屏幕截图是我每次都得到的。
在 Angular 15 中,当组件的封装设置为 Viewencapsulation.Emulate 时,图标会显示在父页面上包含的字体库中。
我对基于角度元素的微前端也遇到了类似的问题,并在根组件中设置了
ViewEncapsulation.ShadowDom
。角度材质组件未设计样式。
为什么不起作用
我对代码的深入研究表明
<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);
}