【问题标题】:What to use in place of ::ng-deep用什么代替 ::ng-deep
【发布时间】:2018-04-11 23:06:51
【问题描述】:

我正在尝试以角度设置路由器插座放置的元素的样式,并希望确保生成的元素的宽度为 100%

从大多数回复中,我看到我应该使用 ::ng-deep 选择器,但从 Angular 的 docs 来看,它已被弃用。 ::ng-deep 有替代品吗?

【问题讨论】:

  • ::ng-deep 不会去任何地方。它始终是您可以启用的设置。如果没有大规模的社区强烈反对,他们现在绝对不可能将其删除。看看这个搜索返回了多少结果 github.com/search?q=%3A%3Ang-deep&type=Code - 这就像说 css !important 属性将消失
  • 我不知道——出于好奇,我在我们的 mono-repo(多个相当大的企业应用程序)中进行了项目范围的搜索,结果只找到了 69 个引用。我觉得这绝对是一个可以接受的重构,以摆脱弃用,并且在他们提出替代方案时很乐意这样做。此外,!important 在 CSS 规范中占有重要地位,而 ::deep 始终只是一个提议。

标签: html css angular


【解决方案1】:

FWIW 在我的研究中,我没有找到任何替代 ng-deep 或其他适用替代品的方法。这是因为,我相信 Angular 团队在遵循 W3C 对 shadow dom 的规范,该规范最初有诸如 deep 之类的选择器。然而,W3c 此后删除了该建议,但没有用新的建议取而代之。在此之前,我想 Angular 团队将保留::ng-deep 并且它的替代品可用,但由于 W3C 草案的未决状态而处于弃用状态。我现在无法花时间找到支持此内容的文档,但我最近确实看到了。

长话短说:继续使用 ::ng-deep 及其替代品,直到创建替代品 - 弃用只是提前通知,这样人们就不会在实际变化发生时措手不及。

-- 更新--

https://drafts.csswg.org/css-scoping-1/ 如果您有兴趣,这里是提案草案。看起来他们正在为 shadow dom 树中的元素开发一组健壮的选择器;正是这个规范,一旦获得批准,我认为它会通知 Angular 克隆,如果有的话(即,一旦它在浏览器中上线,Angular 可能不需要实现自己的选择器)。

【讨论】:

  • 我也愿意。但别无选择,我认为这里已经清楚地概述了这一点。你有什么建议可以帮助解决这个问题吗?
  • 我能很快想到的唯一选择是重构组件的嵌套,这可能比你有时间做的工作更多,但可能会产生其他好处......
  • 借助第三方库,几乎不可能避免偶尔使用::ng-deep(如果您完全关心您的网站的外观)——即使使用像角材料这样的东西。他们有几个月没有修复的错误,解决方法通常涉及 ng-deep。并且不要混淆不同的弃用“深度”选择器 - ::ng-deep 绝对是最不弃用的选择器。
  • 是的,这是整个系统中最丑陋的部分之一。但是封装就是封装。您必须通过在 css 中显式使用 ::ng-deep 来打破边界,或者您需要以编程方式进行。我们有时在组件标签上使用属性来指示组件处于什么“模式”(即上下文),然后样式可以通过属性选择器存在于子组件中而没有 ::ng-deep,例如:@987654329 @ - 这取决于您想要什么样的灵活性/便携性。我不太喜欢这两种方式,但这是封装的世界。
  • 正在进行讨论:Clarify information about deprecation of :ng-deep and recommend replacement 和最近的一篇博客文章,其中包含关于 Future of overriding styles 的声明
【解决方案2】:

深度样式的简单替代方案是使用父组件的元素选择器的常见样式。所以如果你在 hero-details.component.css 中有这个:

:host ::ng-deep h3 {
  font-style: italic;
}

它会在styles.css中变成这样:

app-hero-details h3 {
  font-style: italic;
}

基本上,深度样式是一种未封装的样式,因此从概念上讲,它对我来说更像是一种常见的样式,而不是组件样式。就我个人而言,我不会再使用深度样式了。重大版本更新中的重大更改是正常的,删除已弃用的功能是公平的游戏。

【讨论】:

  • 哇,我现在感觉很笨。谢谢!来自其他前端框架,我认为这是不可能的
  • 这真的很有用。遗憾的是 ::ng-deep 被弃用了这么久而没有替代品( :host::ng-deep 按预期工作,但我不想使用弃用的东西)。
  • 我很困惑,这应该如何工作?如果您在父组件中指定 app-hero-details h3 { ... },它将被封装并且不会影响子组件中的 h3。如果您建议在一般共享样式中使用它,那么可以,但我相信不应该这样做。
  • 此解决方案消除了组织、延迟加载等带来的好处。AliF50 的解决方案更可取 imo
【解决方案3】:

为了绕过已弃用的::ng-deep,我通常禁用ViewEncapsulation。虽然这不是最好的方法,但它对我很有帮助。

要禁用ViewEncapsulation,请在您的组件中执行以下操作:

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

这将使该组件中的 .scss 样式对整个应用程序都是全局的。为了不让样式沿链向上到达父组件和兄弟组件,请使用选择器将整个 scss 包装起来,如下所示:

app-header {
  // your styles here and any child component styles can go here
}

现在,此处指定的样式将归结为子组件,因此您必须更加具体地使用您的 css 选择器,并在添加 CSS 时注意您的 p 和 q(可能添加在您的 Angular 应用程序中指定的子选择器,然后添加它的样式)。

由于上面的段落,我说这不是最好的方法,但这对我很有帮助。

【讨论】:

  • 这只是一种解决方法,如果您有大型项目,关闭ViewEncapsulation 会使这些样式可能泄漏到所有组件中,从而造成很大的损害。 This feature should be used wisely and with full understanding
  • @mpro 我明白,这就是为什么我提出警告并说这不是最好的方法,你必须注意你的 p 和 q 并且必须更加具体。对我来说,这种方法到目前为止效果很好。 ::ng-deep 被标记为弃用,这是一种解决方法。
  • 老实说,如果您因为受到弃用威胁而这样做,我认为这是一个可怕的结论。是的,我知道你也承认这一点,但我真的认为你这样做是在自取其辱。视图封装非常有用,原因有很多。然而,它并不像 Angular 团队中的任何人在没有任何合乎逻辑的解决方法的情况下弃用它并导致许多人感到困惑那样糟糕。归根结底,您仍在为 Web 浏览器编写代码 - 而不是某种专有的 Angular 引擎。
  • @Simon_Weaver 我尊重您的意见并感谢您的分享。我只是将其浮出水面,因为这是我用来规避弃用的方法。我还提出了警告。
  • @AliF50 “规避弃用”并不是真正的事情。这里真正的问题是,我以前从未见过这种情况,他们弃用了它没有指定替代方法。我的回答(上面已接受的回答)解释了我的假设,即他们为什么这样做(W3C 已弃用它)以符合规范。但是,如果您阅读了这些建议,看起来 ::ng-deep 将被替换为合适的替代方案,这意味着当它可用时,您只需更新您的 ::ng-deep 引用,而不是您的方法需要字面意思重新构建整个应用程序。
【解决方案4】:

如前所述,如果您使用第三方库,几乎不可能避免偶尔使用::ng-deep。但是,当浏览器不再支持 ::ng-deep 时,您将如何处理以前的项目?

要为那一刻做好准备,我将提出以下建议:

  1. 明智地使用 ViewEncapsulation.None。这意味着仅适用于那些需要访问更深层组件的组件。
@Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.scss'],
      encapsulation: ViewEncapsulation.None
    })
  1. 现在,为避免冲突和 CSS 怪异,您应该(通常)始终用类包装组件的模板。所以,example.component.html 应该是这样的:
<section class="app-example-container">
<!-- a third party component -->
<mat-tab-group>
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
</mat-tab-group>
</section>
  1. 同样,根据规则,每个 SCSS 文件的第一行都将针对组件容器。由于没有封装,您可以通过定位第三方组件的类来修改它们。也就是说,example.component.scss 应该是:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}

对未来的自我说明:https://angular.io/guide/component-styles
这应该是寻找官方替代方案/可行方法的第一个地方

【讨论】:

  • But what are you going to do about your previous projects when the ::ng-deep became no longer supported by browsers? 这不是由 Angular cli 编译/填充,所以没有浏览器参与吗?顺便说一句,答案很好。
  • 这实际上是渲染到 CSS 文件中,然后浏览器相应地应用样式。使用:host /deep/ .mat-tab-label 可以实现别名(我认为),这应该转换为::ng-deep。老实说,使用别名似乎更方便,因为 CLI 可以在编译时更改它,但仍然需要执行 ng build 并再次部署。我的决定是在我的所有项目中完全避免::ng-deep :)
  • 是的,避免重新部署是有意义的
【解决方案5】:

这不是 ::ng-deep 的一般替代品,而是问题作者描述的用例:

在特殊情况下,您想要设置由路由器插座插入的元素的样式,有一个优雅的解决方案,使用 CSS 中的相邻邻居选择器:

router-outlet+* {
  /* styling here... */
}

这将适用于与路由器插座直接相邻的所有元素。

延伸阅读:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet

【讨论】:

  • 我不推荐使用这个选择器。这似乎是您开启了一场真正的碰撞噩梦,尤其是当您的应用程序增长时。最重要的是,* 选择器实际上是 CSS 中最慢的选择器。
  • @dudewad 虽然 * 选择器是最慢的选择器,但它只应用于字面上的下一个兄弟 (+),而不是整个链/树,所以它应该只产生名义上的差异。跨度>
  • @ErikPhilips CSS 选择器是从右到左解析的,所以这实际上是最坏的情况。
  • @dudewad 我认为我们遗漏了一些东西。 * 是最坏的情况,紧随其后的是 element *,但 element + * 与前两者相差甚远。
  • 我不知道...我没有测试过,这只是基于我对 CSS 解析器如何工作的了解。
【解决方案6】:

您可以使用“/deep/”。这是 ::ng-deep 的替代方案。

:host /deep/ h3 {
  font-style: italic;
}

【讨论】:

猜你喜欢
  • 2019-08-11
  • 1970-01-01
  • 2018-01-08
  • 2016-06-14
  • 1970-01-01
  • 2020-09-07
  • 2020-08-11
  • 1970-01-01
相关资源
最近更新 更多