【问题标题】:How to encapsulate Angular app's global CSS within exported web component?如何在导出的 Web 组件中封装 Angular 应用程序的全局 CSS?
【发布时间】:2021-03-03 21:40:29
【问题描述】:

目标

我有一个 Angular 11 站点,其中包含一个使用 Angular Material 的大型表单组件——我们称之为myExportableComponent。我想像往常一样在我的网站中使用myExportableComponent,但将其导出为通用 Web 组件(又名“自定义元素”,又名“Angular 元素”)。这样一来,它就可以在任何第三方网站上使用,而不管他们的技术堆栈如何,并且它的工作方式与在我的网站上完全相同。

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>

我通过进入angular.json 并将其指向主应用程序的theme.scss 文件(生成的Angular 材质主题)和styles.scss(其他全局样式)使myExportableComponent 与我的主站点共享所有样式.像这样的……

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(材料)样式似乎没有泄漏,但我认为那是因为那些东西已经使用了自定义选择器。我担心如果消费网站碰巧也使用了 Angular Material,它泄露出去。

想法 #1:封装设置

我想尝试在myExportableComponent 上使用encapsulation: ViewEncapsulation.ShadowDom,但是 A) 破坏了一些 Material 样式和图标,并且 B) 这并不是我真正想要的,因为那是组件级封装,我的问题在于全局 CSS。实际上,我的组件特定 CSS 似乎已经使用默认设置进行了封装。

想法 #2:仅将全局 CSS 定位到我的 HTML

如果我在我的应用程序的 HTML 标记中添加了一个类,并让 Web 组件的使用者也将它添加到组件周围,我可以将我的所有全局 CSS 规则定位为仅影响这些容器内的内容,例如:

.special-wrapper a {
   /* some style*/
}

这实际上确实可以封装我来自 3rd 方页面的全局样式,但它会以某种方式翻转样式,以便全局样式在不应该时优先于特定于组件的样式。

想法 #3:在我的全局 CSS 上使用 :host 或 :host-context 选择器?

老实说,我很难掌握这些,而且我无法让它们在我的应用中执行任何操作。

想法 #4:构建时脚本?

myExportableComponent 的子项目构建时,如果我可以自动从theme.scssstyles.scss 剪切所有全局CSS 并将其粘贴到my-exportable.component.scss 的顶部,我认为这会起作用。然后,我的“全局”样式将被封装到我的 Web 组件中,因为它们位于特定于组件的文件中。

当我运行ng build myExportableComponentApp --prod 时可以做这样的事情吗?我不知道从哪里开始。

我愿意接受建议!

【问题讨论】:

    标签: css angular web-component angular-elements


    【解决方案1】:

    这是我最终做的:

    1. angular.json 中删除站点的全局style.scss子项目

    2. 创建一个继承自myExportableComponent 的新组件,但除此之外没有代码。它也没有自己的模板——它共享基本组件的模板。您实际上甚至不需要从子项目中的模块中导出此组件。这样主应用程序默认只能使用基础应用程序,这很好。

    3. 新子组件的 styleUrls 有两个文件。首先是特定于组件的样式表。它的设置和正常一样,但在其中只有一个引用主站点全局样式表的导入,例如@import '../../../../../../src/app/styles.scss';。我想直接引用它,但总是遇到奇怪的构建错误,所以在“正常”组件特定样式表中导入它的技巧很有效。第二个文件是对 base 组件的常规组件特定样式表的引用。

    4. 在为 web 组件做createCustomElement 时,使用子组件而不是父组件。

    最重要的是,在构建通用 Web 组件时,主站点的全局 css 将包含在 myExportableComponent 的组件特定 css 的顶部,而不是全局的。然后封装全局样式,并且仍然可以像正常一样被组件特定样式覆盖。

    我想对包含 Material 主题的 theme.scss 做同样的事情,但它似乎只有在它真正在全局范围内 (https://github.com/angular/components/issues/3386) 时才有效。目前,这对我来说不是一个交易破坏者。

    专业人士:

    • 主站点项目没有特殊设置或中断。它和myExportableComponent 可以在我们的主应用程序中以完全标准的方式使用。
    • 样式封装在导出的 Web 组件中的工作方式与在我们的主项目中的工作方式相同,并且不会泄露到第三方网站。
    • 不需要特殊的构建脚本

    缺点:

    • 这有点不合常规,您需要确保其他开发人员不会在充当此构建解决方案管道的虚拟/继承文件中添加任何内容。
    • 据我所知,Material 主题 css 尚无法实现。

    【讨论】:

    • 我今天遇到了这个问题。这仍然是您在导出的 Web 组件中封装全局 css 的首选方式吗?
    • 是的,该项目尚未启动,但这就是我正在做的事情。我很惊讶这不是更简单的解决方案更常见的问题。
    猜你喜欢
    • 2021-11-01
    • 2016-11-26
    • 2023-03-22
    • 1970-01-01
    • 2018-12-13
    • 2020-11-10
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    相关资源
    最近更新 更多