如何解决如何在导出的 Web 组件中封装 Angular 应用的全局 CSS?
目标
我有一个 Angular 11 站点,其中包含一个使用 Angular Material 的大型表单组件——我们称之为 myExportableComponent
。我想像往常一样在我的网站中使用 myExportableComponent
,但也将其导出为通用 Web 组件(也称为“自定义元素”,也称为“角度元素”)。这样,它就可以在任何 3rd 方网站上使用,无论他们的技术堆栈如何,而且它的工作方式与在我的网站上完全相同。
myExportableComponent
应该像我网站中的普通 Angular 组件一样工作 - 它应该可以通过 styles.scss
中的全局 CSS 和 my-exportable.component.scss
中的组件特定 CSS 设置样式。>
当用作 Web 组件时,myExportableComponent
也应该像平常一样受到全局和特定于组件的 CSS 的影响,但这些 CSS 不应泄漏并影响它所在的第 3 方页面的其余部分放置。这是我正在努力解决的部分。
设置
我在主项目的子项目中设置了 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>
我已经让 myExportableComponent
与我的主站点共享所有样式,方法是进入 angular.json
,并将其指向主应用程序的 theme.scss
文件(生成的 Angular 材质主题)和 {{ 1}}(其他全局样式)。这样的事情...
angular.json:
styles.scss
问题
在其他站点上使用 Web 组件时,不会封装全局 CSS。例如,如果我在 "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"
],
中为我的应用添加全局链接样式,它也会影响消费站点上的所有链接。 styles.scss
(Material) 样式似乎没有泄漏,但我认为那是因为那些东西已经使用了自定义选择器。如果消费站点碰巧也使用 Angular Material,我担心它会泄漏。
想法 1:封装设置
我想尝试在 theme.scss
上使用 encapsulation: ViewEncapsulation.ShadowDom
,但是 A) 破坏了一些 Material 样式和图标,并且 B) 无论如何这并不是我真正想要的,因为那是组件级封装和我的问题是全局 CSS。实际上,我的组件特定 CSS 似乎已经被默认设置封装了。
想法 2:仅将全局 CSS 定位到我的 HTML
如果我在应用程序的 HTML 标签中添加一个类,并让 Web 组件的使用者也将它添加到组件周围,我可以将所有全局 CSS 规则定位为仅影响这些容器内的内容,例如:
myExportableComponent
这实际上确实可以从 3rd 方页面封装我的全局样式,但它以某种方式翻转了样式,以便全局样式在不应该优先于特定于组件的样式时优先。
想法 3:在我的全局 CSS 上使用 :host 或 :host-context 选择器?
老实说,我很难掌握这些,而且我无法让它们在我的应用中执行任何操作。
想法 4:构建时脚本?
当 .special-wrapper a {
/* some style*/
}
的子项目构建完成后,如果我能自动从 myExportableComponent
和 theme.scss
中剪切所有全局 CSS 并将其粘贴到 styles.scss
的顶部,我认为那会奏效。我的“全局”样式将被封装到我的 Web 组件中,因为它们位于特定于组件的文件中。
当我运行 my-exportable.component.scss
时是否可以做这样的事情?我不知道从哪里开始。
我愿意接受建议!
解决方法
这是我最终做的:
-
从子项目的
style.scss
删除站点的全局angular.json
。 -
创建一个继承自
myExportableComponent
的新组件,但除此之外没有代码。它也没有自己的模板——它共享基本组件的模板。您实际上甚至不需要从子项目中的模块中导出此组件。这样主应用默认只能使用基础的,这很好。 -
新子组件的 styleUrls 有两个文件。首先是特定于组件的样式表。它的设置与正常一样,但在它内部只有一个引用主站点全局样式表的导入,类似于
@import '../../../../../../src/app/styles.scss';
。我想直接引用它,但不断收到奇怪的构建错误,因此将它导入到“普通”特定于组件的样式表中的技巧是有效的。第二个文件是对 base 组件的常规组件特定样式表的引用。 -
为 Web 组件执行
createCustomElement
时,使用子组件而不是父组件。
最重要的是,在构建通用 Web 组件时,主站点的全局 css 将包含在 myExportableComponent
的组件特定 css 的顶部,而不是全局的。然后封装全局样式,并且仍然可以像正常一样被特定于组件的样式覆盖。
我想对包含 Material 主题的 theme.scss
做同样的事情,但它似乎只有在它真正在全局范围内 (https://github.com/angular/components/issues/3386) 时才有效。目前这对我来说不是一个交易破坏者。
优点:
- 主站点项目没有特殊设置或中断。它和
myExportableComponent
可以在我们的主应用中以完全标准的方式使用。 - 样式封装在导出的 Web 组件中的工作方式与在我们的主项目中的工作方式相同,并且不会泄露到 3rd 方网站。
- 不需要特殊的构建脚本
缺点:
- 这有点不正统,您需要确保其他开发人员不会在用作此构建解决方案管道的虚拟/继承文件中放置任何内容。
- 据我所知,Material 主题 css 尚不可行。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。