как стилизовать дочерние компоненты из css-файла родительского компонента?

<p>у меня есть родительский компонент:</p><pre><code><parent></parent> </code></pre><p>и я хочу заполнить эту группу дочерними компонентами:</p><pre><code><parent> <child></child> <child></child> <child></child> </parent> </code></pre><p>родительский шаблон:</p><pre><code><div class="parent"> <!-- children goes here --> <ng-content></ng-content> </div> </code></pre><p>детский шаблон:</p><pre><code><div class="child">test</div> </code></pre><p>поскольку <code>parent</code> и <code>child</code> являются двумя отдельными компонентами, их стили привязаны к собственной области видимости. </p><p>в моем родительском компоненте я попытался сделать:</p><pre><code>.parent .child { // styles for child } </code></pre><p>но стили <code>.child</code> не применяются к компонентам <code>child</code>.</p><p>я попытался использовать <code>styleurls</code> для включения таблицы стилей <code>parent</code> в компонент <code>child</code> для решения проблемы области:</p><pre><code>// child.component.ts styleurls: [ './parent.component.css', './child.component.css', ] </code></pre><p>но это не помогло, также попробовал другой способ, загрузив таблицу стилей <code>child</code> в <code>parent</code>, но это тоже не помогло.</p><p>так как же стилизовать дочерние компоненты, которые включены в родительский компонент?</p>

<h1>обновление - новейший путь</h1><p>не делай этого, если можешь этого избежать. как отмечает девон санс в комментариях: эта функция, скорее всего, будет устаревшей.</p><h1>обновление - новый путь</h1><p>начиная с <strong>angular 4.3.0</strong>, все прокалывающие комбинаторы css устарели. команда angular представила новый комбинатор <strong><code>::ng-deep</code> (все еще на экспериментальном уровне, а не полным и окончательным способом)</strong>, как показано ниже,</p><p><strong>demo: <a href="https://plnkr.co/edit/rbjiszu14o4svhlqt563?p=preview">https://plnkr.co/edit/rbjiszu14o4svhlqt563?p=preview</a> </strong></p><pre><code>styles: [ ` :host { color: red; } :host ::ng-deep parent { color:blue; } :host ::ng-deep child{ color:orange; } :host ::ng-deep child.class1 { color:yellow; } :host ::ng-deep child.class2{ color:pink; } ` ], template: ` angular2 //red <parent> //blue <child></child> //orange <child class="class1"></child> //yellow <child class="class2"></child> //pink </parent> ` </code></pre><p><hr></p><h1>старый способ</h1><p>вы можете использовать <code>encapsulation mode</code> и/или <code>piercing css combinators >>>, /deep/ and ::shadow</code></p><p>рабочий пример: <a href="http://plnkr.co/edit/1rbdgq?p=preview">http://plnkr.co/edit/1rbdgq?p=preview</a> </p><pre><code>styles: [ ` :host { color: red; } :host >>> parent { color:blue; } :host >>> child{ color:orange; } :host >>> child.class1 { color:yellow; } :host >>> child.class2{ color:pink; } ` ], template: ` angular2 //red <parent> //blue <child></child> //orange <child class="class1"></child> //yellow <child class="class2"></child> //pink </parent> ` </code></pre>

<p><strong>обновление 3:</strong></p><p><code>::ng-deep</code> также устарел, что означает, что вы больше не должны этого делать. неясно, как это влияет на вещи, где вам нужно переопределить стили в дочерних компонентах родительского компонента. мне кажется странным, если это будет удалено полностью, потому что как это повлияет на вещи как библиотеки, где вам нужно переопределить стили в компоненте библиотеки?</p><p>прокомментируйте, если у вас есть понимание этого.</p><p><strong>обновление 2:</strong></p><p>поскольку <code>/deep/</code> и все другие теневые пирсинг-селекторы устарели. angular drop <code>::ng-deep</code>, который следует использовать вместо этого для более широкой совместимости. </p><p><strong>обновление:</strong></p><p>если вы используете angular-cli, вам нужно использовать <code>/deep/</code> вместо <code>>>></code>, иначе он не будет работать. </p><p><strong>оригинал:</strong></p><p>после перехода на страницу github на angular2 и случайного поиска «style» я нашел этот вопрос: <a href="https://stackoverflow.com/questions/36265026/angular-2-innerhtml-styling">angular 2 - stylehtml</a> </p><p>который сказал использовать что-то, что было добавлено в <code>2.0.0-beta.10</code>, <code>>>></code> и <code>::shadow</code> селекторы. </p><blockquote> <blockquote> <p>(>>>) (и эквивалент/deep /) и :: shadow были добавлены в 2.0.0-beta.10. они похожи на css-комбинаторы теневого dom (которые устарели) и работают только с инкапсуляцией: viewencapsulation.emulated, которая используется по умолчанию в angular2. они, вероятно, также работают с viewencapsulation.none, но затем игнорируются только потому, что в них нет необходимости. эти комбинаторы являются лишь промежуточным решением, пока не поддерживаются более продвинутые функции для многокомпонентного моделирования.</p> </blockquote> </blockquote><p>так просто делаешь</p><pre><code>:host >>> .child {} </code></pre><p>в файле стилей <code>parent</code> проблема решена. обратите внимание, что, как указано в приведенной выше цитате, это решение является промежуточным, пока не поддерживается более продвинутый межкомпонентный стиль.</p>

<p>возникла та же проблема, поэтому, если вы используете angular2-cli с scss/sass, используйте «/ deep /» вместо «>>>», последний селектор еще не поддерживается (но отлично работает с css).</p>

<p>к сожалению, похоже, что/deep/selector устарел (по крайней мере, в chrome) <a href="https://www.chromestatus.com/features/6750456638341120">https://www.chromestatus.com/features/6750456638341120</a> </p><p>короче говоря, кажется, что (в настоящее время) нет долгосрочного решения, кроме как каким-то образом заставить ваш дочерний компонент динамически стилизовать вещи . <br/><br/> вы можете передать объект стиля вашему ребенку и применить его через:<br/> <code><div [attr.style]="styleobject"></code><br/><br/> или, если у вас есть определенный стиль, вы можете использовать что-то вроде:<br/> <code><div [style.background-color]="colorvar"></code></p><p>дополнительные обсуждения, связанные с этим: <a href="https://github.com/angular/angular/issues/6511">https://github.com/angular/angular/issues/6511</a> </p>

<p>если вы хотите быть более нацеленным на фактический дочерний компонент, чем вы должны сделать следующее. таким образом, если другие дочерние компоненты имеют одинаковое имя класса, они не будут затронуты. </p><p>плункер: <a href="https://plnkr.co/edit/oobrp3rok6fbwputoyto?p=preview">https://plnkr.co/edit/oobrp3rok6fbwputoyto?p=preview</a> </p><p>например:</p><pre><code>import {component, ngmodule } from '@angular/core' import {browsermodule} from '@angular/platform-browser' @component({ selector: 'my-app', template: ` <div> <h2>i'm the host parent</h2> <child-component class="target1"></child-component><br/> <child-component class="target2"></child-component><br/> <child-component class="target3"></child-component><br/> <child-component class="target4"></child-component><br/> <child-component></child-component><br/> </div> `, styles: [` /deep/ child-component.target1 .child-box { color: red !important; border: 10px solid red !important; } /deep/ child-component.target2 .child-box { color: purple !important; border: 10px solid purple !important; } /deep/ child-component.target3 .child-box { color: orange !important; border: 10px solid orange !important; } /* this won't work because the target component is spelled incorrectly */ /deep/ xxxxchild-component.target4 .child-box { color: orange !important; border: 10px solid orange !important; } /* this will affect any component that has a class name called .child-box */ /deep/ .child-box { color: blue !important; border: 10px solid blue !important; } `] }) export class app { } @component({ selector: 'child-component', template: ` <div class="child-box"> child: this is some text in a box </div> `, styles: [` .child-box { color: green; border: 1px solid green; } `] }) export class childcomponent { } @ngmodule({ imports: [ browsermodule ], declarations: [ app, childcomponent ], bootstrap: [ app ] }) export class appmodule {} </code></pre><p>надеюсь это поможет!</p><p>codematrix</p>

<p>если вы не хотите использовать :: ng-deep, вы можете сделать это так, как вам кажется:</p><pre><code>import { viewencapsulation } from '@angular/core'; @component({ .... encapsulation: viewencapsulation.none }) </code></pre><p>и тогда вы сможете изменить css форму вашего компонента без необходимости из :: ng-deep</p><pre><code>.mat-sort-header-container { display:flex; justify-content:center; } </code></pre><p>внимание: будьте осторожны, так как если ваш компонент имеет много дочерних элементов, css, который вы пишете для этого компонента, может повлиять на все дочерние элементы!</p>

<p>есть несколько вариантов для достижения этой цели в angular:</p><p>1) вы можете использовать глубокие селекторы css</p><pre><code>:host >>> .childrens { color: red; } </code></pre><p>2) вы также можете изменить инкапсуляцию вида, для нее установлено значение эмуляция по умолчанию, но ее можно легко изменить на native, который использует реализацию собственного браузера shadow dom, в вашем случае вам просто нужно отключить ее. </p><p>например:</p><pre><code>import { component, viewencapsulation } from '@angular/core'; @component({ selector: 'parent', styles: [` .first { color:blue; } .second { color:red; } `], template: ` <div> <child class="first">first</child> <child class="second">second</child> </div>`, encapsulation: viewencapsulation.none, }) export class parentcomponent { constructor() { } } </code></pre>

<p>я считаю, что<strong> намного чище передавать переменную @input </strong>, если у вас есть доступ к коду дочернего компонента:</p><p>идея состоит в том, что родитель сообщает ребенку, каким должно быть его состояние внешнего вида, а ребенок решает, как отобразить это состояние. это хорошая архитектура </p><p><strong> scss путь: </strong></p><pre><code>.active { ::ng-deep md-list-item { background-color: #eee; } } </code></pre><p><strong> лучший способ: </strong>- использовать переменную <code>selected</code>:</p><pre><code><md-list> <a *ngfor="let convo of conversations" routerlink="/conversations/{{convo.id}}/messages" #rla="routerlinkactive" routerlinkactive="active"> <app-conversation [selected]="rla.isactive" [convo]="convo"></app-conversation> </a> </md-list> </code></pre>

<p>не следует писать правила css для дочерних элементов компонента в родительском компоненте, поскольку компонент angular является автономной сущностью, которая должна явно декларировать то, что доступно для внешнего мира. если в будущем дочерний макет изменится, ваши стили для элементов этого дочернего компонента, разбросанных по файлам scss других компонентов, могут легко сломаться, что сделает ваш стиль очень хрупким. это то, что <code>viewencapsulation</code> для css. в противном случае было бы то же самое, если бы вы могли присваивать значения частным полям некоторого класса из любого другого класса в объектно-ориентированном программировании.</p><p>поэтому вам нужно определить набор классов, которые вы можете применить к дочернему элементу host, и реализовать, как дочерний элемент реагирует на них.</p><p>технически это можно сделать следующим образом:</p><pre><code>// child.component.html: <span class="label-1"></span> // child.component.scss: :host.child-color-black { .label-1 { color: black; } } :host.child-color-blue { .label-1 { color: blue ; } } // parent.component.html: <child class="child-color-black"></child> <child class="child-color-blue"></child> </code></pre><p>другими словами, вы используете псевдо-селектор <code>:host</code>, предоставляемый angular + набор css-классов, чтобы определить возможные дочерние стили в самом дочернем компоненте. затем у вас есть возможность запускать эти стили извне, применяя предопределенные классы к элементу <code><child></code> host.</p>

<p>у меня также была эта проблема, и я не хотел использовать устаревшее решение, поэтому я закончил с:</p><p>в отрыве</p><pre><code> <dynamic-table containercustomstyle='width: 400px;' > </dynamic-table> </code></pre><p>дочерний компонент</p><pre><code>@input() containercustomstyle: string; </code></pre><p>у ребенка в html div</p><pre><code> <div class="container mat-elevation-z8" [style]='getstyle(containercustomstyle)' > </code></pre><p>и в коде</p><pre><code>constructor(private sanitizer: domsanitizer) { } getstyle(c) { if (isnullorundefined(c)) { return null; } return this.sanitizer.bypasssecuritytruststyle(c); } </code></pre><p>работает как положено и не должно быть устаревшим;)</p>

<p>быстрый ответ: вам вообще не следует этого делать. это нарушает инкапсуляцию компонентов и подрывает выгоду, которую вы получаете от автономных компонентов. подумайте о том, чтобы передать флаг пропуска дочернему компоненту, он может сам решить, как отображать по-другому или применять другой css, если это необходимо.</p><pre><code><parent> <child [foo]="bar"></child> </parent> </code></pre><p>angular осуждает все способы воздействия на дочерние стили от родителей.</p><p> <a href="https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep">https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep</a> </p>

<p>на самом деле есть еще один вариант. что довольно безопасно. вы можете использовать viewencapsulation.none, но поместите все стили вашего компонента в его тег (он же селектор). но в любом случае всегда предпочитайте какой-нибудь глобальный стиль плюс инкапсулированные стили.</p><p>вот модифицированный пример дениса рыбалки:</p><pre><code>import { component, viewencapsulation } from '@angular/core'; @component({ selector: 'parent', styles: [` parent { .first { color:blue; } .second { color:red; } } `], template: ` <div> <child class="first">first</child> <child class="second">second</child> </div>`, encapsulation: viewencapsulation.none, }) export class parentcomponent { constructor() { } } </code></pre>

<p>я предлагаю пример, чтобы сделать его более понятным, поскольку <a href="https://angular.io/guide/component-styles">angular.io/guide/component-styles</a> заявляет:</p><blockquote> <p>пронзающий теневой комбайнатор устарел, и поддержка удаляется из основных браузеров и инструментов. поэтому мы планируем отказаться от поддержки в angular (для всех 3 of/deep /, >>> и :: ng-deep). до тех пор :: ng-deep следует предпочитать для более широкой совместимости с инструментами.</p> </blockquote><p>на <code>app.component.scss</code> импортируйте свой <code>*.scss</code>, если это необходимо. <code>\_colors.scss</code> имеет несколько общих значений цвета:</p><pre><code>$button_ripple_red: #a41e34; $button\_ripple\_white\_text: #fff; </code></pre><p><strong>применить правило ко всем компонентам</strong></p><p>все кнопки, имеющие класс <code>btn-red</code>, будут стилизованы.</p><pre><code>@import `./theme/sass/\_colors`; // red background and white text :host /deep/ button.red-btn { color: $button_ripple_white_text; background: $button\_ripple\_red; } </code></pre><p><strong>применение правила к одному компоненту</strong></p><p>будут стилизованы все кнопки, имеющие класс <code>btn-red</code> в компоненте <code>app-login</code>.</p><pre><code>@import `./theme/sass/\_colors`; /deep/ app-login button.red-btn { color: $button_ripple_white_text; background: $button\_ripple\_red; } </code></pre>