Как и где использовать :: ng-deep?

90

Я новичок в Angular 4, поэтому может ли кто-нибудь объяснить, как и где использовать ::ng-deepв Angular 4?

На самом деле я хочу перезаписать некоторые свойства CSS дочерних компонентов из родительских компонентов. Более того, поддерживается ли это в IE11?

Джеябалан Тавамани
источник
Так /deep/и ::ng-deepоба устарели, я предлагаю вам принять к этому советует сначала ответ stackoverflow.com/a/49308475/2275011 и комментарии для получения более подробной информации и решений.
Ferie

Ответы:

92

Обычно /deep/ “shadow-piercing”комбинатор можно использовать, чтобы изменить стиль до child components. У этого селектора был псевдоним >>>, а теперь есть еще один - :: ng-deep.

поскольку /deep/ combinatorустарел, рекомендуется использовать::ng-deep

Например:

<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>

а также css

.overview {
    ::ng-deep {
        p {
            &:last-child {
                margin-bottom: 0;
            }
        }
    }
}

он будет применен к дочерним компонентам

Саджитаран
источник
Это поддержка IE11?
Jeyabalan Thavamani
2
Angular выполняет его анализ, поэтому вам не нужно беспокоиться о совместимости.
Simon_Weaver
это только для дочерних компонентов? как я помню и как я вижу в другом комментарии, это также для элементов dom вне компонента.
yaya
Я могу подтвердить, что это относится и к родительским компонентам ... Просто был случай, и меня это раздражало.
Shadoweb
1
Круто, отлично сработало.
Альфредо Замудио,
70

ПРИМЕНЕНИЕ

::ng-deep, >>>И /deep/отключить просмотр инкапсуляция для конкретных правил CSS, другими словами, это дает вам доступ к элементам DOM, которые не находятся в HTML вашего компонента. Например, если вы используете Angular Material (или любую другую подобную стороннюю библиотеку), некоторые сгенерированные элементы находятся за пределами области вашего компонента (например, диалог ), и вы не можете получить доступ к этим элементам напрямую или с помощью обычного CSS. путь. Если вы хотите изменить стили этих элементов, вы можете использовать одну из этих трех вещей, например:

::ng-deep .mat-dialog {
  /* styles here */
}

На данный момент команда Angular рекомендует производить «глубокие» манипуляции только с ЭМУЛИРОВАННОЙ инкапсуляцией представления.

УДАЛЕНИЕ

«глубокие» манипуляции на самом деле тоже устарели , НО они все еще работают, потому что Angular поддерживает предварительную обработку (не спешите отказываться ::ng-deepсегодня, сначала взгляните на методы устаревания ).

В любом случае, прежде чем следовать этому пути, я рекомендую вам взглянуть на отключение подхода инкапсуляции представления (который тоже не идеален, он позволяет вашим стилям просачиваться в другие компоненты), но в некоторых случаях это лучший способ. Если вы решили отключить инкапсуляцию представления, настоятельно рекомендуется использовать определенные классы, чтобы избежать пересечения правил CSS и, наконец, избежать беспорядка в ваших таблицах стилей. Отключить действительно просто прямо в .tsфайле компонента :

@Component({
  selector: '',
  template: '',
  styles: [''],
  encapsulation: ViewEncapsulation.None  // Use to disable CSS Encapsulation for this component
})

Вы можете найти больше информации об инкапсуляции представления в этой статье.

Коммерческое самоубийство
источник
3
Отключение инкапсуляции представления применяет весь CSS в вашем компоненте глобально.
Vedran
17
Не используйте ViewEncapsulation.None! Это нанесет большой ущерб, поскольку эти стили могут проникнуть в другие компоненты.
Alex Klaus
1
@AlexKlaus, согласен, поэтому я упомянул в ответе, что это не идеально. Фактически, я использовал его только один раз, чтобы применить общие повторяемые стили к компонентам Angular Material. Если вы попытаетесь отключить инкапсуляцию, возможно, в какой-то момент вы получите беспорядок. Об этой опции полезно знать, но не используйте ее, пока вы не совсем уверены, что она вам нужна.
Коммерческое самоубийство
29

Я бы подчеркнул важность ограничения ::ng-deepтолько дочерними элементами компонента, требуя, чтобы родитель был инкапсулированным классом css.

Чтобы это работало, важно использовать ::ng-deepпосле родителя, а не раньше, иначе он будет применяться ко всем классам с тем же именем в момент загрузки компонента.

Компонент css:

.my-component ::ng-deep .mat-checkbox-layout {
    background-color: aqua;
}

Шаблон компонента:

<h1 class="my-component">
    <mat-checkbox ....></mat-checkbox>
</h1>

Результирующий (сгенерированный на Angular) css:

.my-component[_ngcontent-c1] .mat-checkbox-layout {
    background-color: aqua;
}

РЕДАКТИРОВАТЬ:

Вы можете добиться того же поведения, используя :hostключевое слово вместо создания нового класса css.

:host ::ng-deep .mat-checkbox-layout
Ведран
источник
5
чувак, твой ответ my-component ::ng-deep...только спас мне день. Я потратил весь день, пытаясь применить стиль для моего компонента с помощью ng-deep, и переопределил все мои компоненты из всего моего приложения.
Криштиану Бомбазар
2
Стоит отметить: «Чтобы применить указанный стиль к текущему компоненту и всем его потомкам [но не глобально], не забудьте включить селектор: host перед :: ng-deep». От: angular.io/guide/component-styles
StvnBrkdll
1
@CristianoBombazar - вы получите такое же поведение с :hostключевым словом - добавлено примечание к ответу для ясности.
Ведран
23

Убедитесь, что вы не пропустите объяснение, :host-contextкоторое находится прямо выше ::ng-deepв угловом руководстве: https://angular.io/guide/component-styles . Отказ от ответственности: я пропустил это до сих пор и хотел бы увидеть его раньше.

::ng-deepчасто бывает необходимо, когда вы не писали компонент и не имеете доступа к его источнику, но :host-contextможет быть очень полезным вариантом, когда вы это делаете.

Например, у меня есть черный <h1>заголовок внутри компонента, который я разработал, и мне нужна возможность изменить его на белый, когда он отображается на темном тематическом фоне.

Если бы у меня не было доступа к источнику, мне, возможно, пришлось бы сделать это в CSS для родителя:

.theme-dark widget-box ::ng-deep h1 { color: white; }

Но вместо этого :host-contextвы можете сделать это внутри компонента.

 h1 
 {
     color: black;       // default color

     :host-context(.theme-dark) &
     {
         color: white;   // color for dark-theme
     }

     // OR set an attribute 'outside' with [attr.theme]="'dark'"

     :host-context([theme='dark']) &
     {
         color: white;   // color for dark-theme
     }
 }

Это будет искать где угодно в цепочке компонентов .theme-darkи применять CSS к h1, если он найден. Это хорошая альтернатива слишком многому, ::ng-deepчто, хотя и часто необходимо, является своего рода антипаттерном.

В этом случае &вместо него используется h1(так работает sass / scss), поэтому вы можете определить свой «нормальный» и тематический / альтернативный CSS рядом друг с другом, что очень удобно.

Будьте осторожны, чтобы получить правильное количество :. Ибо ::ng-deepих два и :host-contextтолько один.

Simon_Weaver
источник
Вы также можете использовать, :host(.theme-dark)если не хотите наследовать theme-darkкакие-либо родительские компоненты. Это будет полностью зависеть от дизайна css вашего сайта. Также атрибуты могут быть очень полезными и их можно сложным образом комбинировать только в css:host([theme='dark']:not([dayofweek='tuesday'))
Simon_Weaver
Также обратите внимание, что это следует обычным правилам css, поэтому, если у вас есть компонент, как описано выше (с css контекста хоста) внутри контейнера, который имеет .theme-lightкласс, он, в свою очередь, вложен внутри контейнера, и .theme-darkон все равно будет подбирать theme-darkи применять css. Но это отличное решение для классов типов «modernizr», или если у вас есть глобальная тема, установленная только один раз.
Simon_Weaver
Могу ли я использовать: host-context вместо :: ng-deep?
Эдди
@eddy Я слишком сонный сейчас, чтобы полностью обдумать это, но host-context почти как ng-deep, но идет вверх по дереву DOM, а не вниз. Так что это абсолютно не эквивалентно, но вы могли бы
Simon_Weaver
2

Просто обновление:

Вы должны использовать ::ng-deepвместо того, /deep/что кажется устаревшим.

В документации:

Комбинатор потомков с пропусканием теней устарел, и его поддержка прекращается из основных браузеров и инструментов. По этой причине мы планируем отказаться от поддержки Angular (для всех трех из / deep /, >>> и :: ng-deep). До тех пор следует предпочесть :: ng-deep для более широкой совместимости с инструментами.

Вы можете найти это здесь

Балаж Такач
источник
5
В этом тексте четко сказано, что :: ng-deep также устарел: «мы планируем отказаться от поддержки в Angular (для всех трех из / deep /, >>> и :: ng-deep)».
adripanico
-2

Используйте :: ng-deep с осторожностью. Я использовал его во всем своем приложении, чтобы настроить цвет панели инструментов материального дизайна на разные цвета во всем моем приложении, только чтобы обнаружить, что, когда приложение тестировало, цвета панели инструментов накладываются друг на друга. Чтобы узнать, что это происходит из-за того, что эти стили становятся глобальными, см. Эту статью. Вот решение для рабочего кода, которое не распространяется на другие компоненты.

<mat-toolbar #subbar>
...
</mat-toolbar>

export class BypartSubBarComponent implements AfterViewInit {
  @ViewChild('subbar', { static: false }) subbar: MatToolbar;
  constructor(
    private renderer: Renderer2) { }
  ngAfterViewInit() {
    this.renderer.setStyle(
      this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
  }

}
Post Impatica
источник