目标
我有一个使用Angular Material的大型表单组件,名为myExportableComponent
,版本为Angular 11。我想在我的网站中像平常一样使用myExportableComponent
,同时也想将它导出为通用的Web组件(也叫“自定义元素”或“Angular Element”)。这样,无论第三方网站使用什么技术堆栈,都可以使用它,并且它可以像在我的网站上一样正常工作。
在我的网站中,myExportableComponent
应该像正常的Angular组件一样工作-它应该可以通过styles.scss
中的全局CSS和my-exportable.component.scss
中的特定于组件的CSS进行样式设置。
当作为Web组件使用时,myExportableComponent
也应该像正常一样受到全局和特定于组件的CSS的影响,但是所有的CSS都不应该泄漏并影响放置它的第三方页面的其他部分。这就是我遇到的问题所在。
设置
我已经在主项目的子项目中设置了myExportableComponent
。我可以分别构建它,并取得生成的js/css文件,成功地在另一个网站中使用Web组件。类似于这样:
<link rel="stylesheet" href="myExportableComponentStyles.css">
<script type="text/javascript" src="myExportableComponent.js"></script>
<div class="mat-app-background mat-typography">
<my-exportable-component></my-exportable-component>
</div>
我已经在 angular.json
文件中,将 myExportableComponent
与主站点共享样式,指向了主应用程序的 theme.scss
文件(生成的 Angular Material 主题)以及 styles.scss
(其他全局样式)。像这样...
angular.json:
"mainApp": {
...
"styles": [
"src/theme.scss",
"src/styles.scss"
],
"myExportableComponentApp": {
...
"styles": [
"src/theme.scss", //NOT "projects/myExportableComponentApp/src/theme.scss"
"src/styles.scss" //NOT "projects/myExportableComponentApp/src/styles.scss"
],
问题
当Web组件在另一个站点上使用时,全局CSS未被封装。例如,如果我在styles.scss
中为我的应用添加一个全局链接样式,它也会影响消费站点上的所有链接。 theme.scss
(Material)样式似乎不会泄漏出来,但我认为这是因为该内容已经使用了自定义选择器。我担心如果消费站点也使用Angular Material,则它将泄漏出来。
想法#1:封装设置
我考虑尝试在myExportableComponent
上使用encapsulation: ViewEncapsulation.ShadowDom
,但是A)这会破坏一些Material样式和图标,并且B)这实际上并不是我想要的,因为这是组件级别的封装,而我的问题是关于全局CSS。实际上,我的特定于组件的CSS似乎已经使用默认设置进行了封装。
想法#2:将全局CSS目标定位到我的HTML
如果我向应用程序的HTML标记添加类,并要求Web组件的消费者在组件周围也添加该类,则可以将所有全局CSS规则定位到仅影响这些容器内的内容,例如:
.special-wrapper a {
/* some style*/
}
尝试了一些方法后,发现将全局样式从第三方页面中封装确实可行,但是这种做法会导致全局样式在不应该的情况下占优势。
想法#3:在我的全局CSS中使用:host或:host-context选择器?
老实说,我很难理解它们,并且我无法在我的应用程序中让它们起作用。
想法#4:构建时脚本?
当构建myExportableComponent
子项目时,如果我可以自动从theme.scss
和styles.scss
中剪切所有全局CSS并将其粘贴到my-exportable.component.scss
的顶部,我认为那会奏效。因为“全局”样式将被封装到Web组件中,因为它们在组件特定文件中。
在运行ng build myExportableComponentApp --prod
时是否可能做到这样的事情?我不知道从哪里开始。
欢迎提出建议!