AngularDartの別のコンポーネントにCSSクラスを適用する方法は?


8

ポップアップを表示するシンプルなフレームワークがあるとしましょう:

@Component(
  selector: 'popup-host',
  template: '''
      <div class="popup-container">
        <ng-template #popupRef></ng-template>
      </div>
  ''',
  styles: ['.popup-container { position: absolute; top: 100; left: 100; z-index: 100; }'],
)
class PopupContainerComponent {
  final PopupController _controller;
  final ComponentLoader _loader;

  PopupContainerComponent(this._controller, this._loader);

  void ngOnInit() {
    _controller.container = this;
  }

  @ViewChild('popupRef', read: ComponentRef)
  ComponentRef popupRef;

  void render(PopupConfig config) {
    final componentRef = _loader.loadNextTo(config.factory, popupRef);
    if (componentRef.instance is HasValueSetter) {
      componentRef.instance.value = config.value;
    }
  }
}

@Injectable()
class PopupController {
  PopupContainerComponent _container;
  set container(PopupContainerComponent container) => _container = container;

  void showPopup(PopupConfig config) {
    container.render(config);
  }
  ...
}

class PopupConfig {
  final ComponentFactory factory;
  final dynamic value;
  PopupConfig(this.factory, [this.value]);
}

abstract class HasValueSetter {
  set value(dynamic value);
}

これは次のように使用できます:

// Somewhere in the root template
<popup-host></popup-host>

// In popup.dart
@Component(
  selector: 'happy-popup',
  template: '''
      <div class="header">This is the popup content.</div>
      <div class="main">The value is {{value}}.</div>
      <div class="footer">I am happy!</div>
  ''',
)
class HappyPopupComponent implements HasValueSetter {
  @override
  dynamic value;
}

// In some_other.dart
@Component(
  ...
  styles: [
    '.header { font-weight: bold }',
    '.main { color: red }',
    '.footer { color: green; font-style: italic }',
  ],
  ...
)
class SomeOtherComponent {
  final PopupController _popupController;
  ...
  SomeOtherComponent(this._popupController, ...) ...;

  void displayPopup() {
    _popupController.showPopup(HappyPopupComponentNgFactory, 42);
  }
}
...

スタイルを転送する方法がある<some-other-component>のを<happy-popup>、アプリのルートにそれらを定義しなくては?

回答:


5

これは、コンポーネントコードを個別のファイル、または場合によっては個別のCSSファイルに分割することで実現できます。

コンポーネントの- stylesにスタイルを直接記述する代わりに、を使用してCSSファイルをインポートしますstyleUrls。これにより、スタイルを含むファイルを渡すことができ、ファイルを複数のコンポーネント間で共有できます。

@Component(
      styleUrls: ['./hero1.css', './folder/hero2.css'],
)

styleUrlsのURLはコンポーネントを基準にしていることに注意してください。

でCSSをインポートするもう1つの利点は、styleUrlsそのファイル内でインポートを使用する機能も付与されることです。

hero1.css

@import './folder/hero2.css';

参考:コンポーネントコードを個別のファイルに分割することは一般的な方法です。

  • hero.dart
  • hero.css
  • hero.html

次に、dartファイルでそれらを次のように参照します。

@Component(
      templateUrl: './hero.html',
      styleUrls: ['./hero.css'],
)

これに関する簡単な情報については、AngularDart-コンポーネントスタイルを参照してください。


ありがとうございました。スタイルシートを別のファイルに分割できることは知っていましたが、複数のコンポーネントでスタイルシートを再利用することについてはあまり考えていませんでした。ただし、このソリューションが十分に普遍的であるかどうかはわかりません。たとえば、ポップアップコンポーネントがフレームワークの一部であり、アプリの一部をフレームワークにインポートすることは、適切なソフトウェアプラクティスに反する場合があります。理想的には、フレームワークは、を介して提供される任意のcssファイルをインポートする方法を提供しますPopupConfigstyleUrls実行時にコンポーネントのプロパティをカスタマイズすることは可能ですか?
Sergiy Belozorov

また、同じポップアップを開きたいが、スタイルを変えたいコンポーネントが複数ある場合はどうなりますか?
Sergiy Belozorov

1
はいstyleUrls、実行時に動的に設定できます。それを行うには複数の方法があります。Angular dynamic styleUrlsいくつかのアイデアを得るために検索して、どれがあなたに一番合うのかを確認することをお勧めします。2番目の質問について。その場合は、共有ポップアップスタイルファイル+特定のコンポーネントに対して変更するスタイルを上書きするスタイルファイルをインポートします。
Dino

2つのポップアップのスタイルを変える方法に関するあなたの提案を理解しているとは思いません。どちらのポップアップも同じコンポーネントを使用するため、共有ファイルからスタイルを上書きできる唯一の方法はstyleUrls、実行時に新しいエントリを追加することですよね。2つのポップアップが同時に表示される場合(たとえば、1つが別のポップアップを開き、別のスタイルにする必要がある場合)を変更するとstyleUrls、両方のスタイルになりますか?最後に、styleUrlsハックせずに動的に変更する方法についての良い記事が見つかりませんでした。Angularでは本来サポートされていないようです。
Sergiy Belozorov

1

ポップアップはそれを開いたコンポーネントの子ではないため、:: ng-deepは使用できません

ホスト、ポップアップ、およびポップアップを開くコンポーネントからビューのカプセル化を削除することだけが機能すると思います(それが機能しない場合は、ホストのカプセル化を削除してください)同様に。)

@Component(
  selector: 'happy-popup',
  template: '''
      <div class="header">This is the popup content.</div>
      <div class="main">The value is {{value}}.</div>
      <div class="footer">I am happy!</div>
  ''',
  encapsulation: ViewEncapsulation.None // <=== no encapsulation at all
)
class HappyPopupComponent implements HasValueSetter {

「ビューのカプセル化を削除する」とはどういう意味ですか?
Sergiy Belozorov

@SergiyBelozorov完了:) それがあなたを助けたかどうか私に知らせてください
Ron

それは確かに私がAngularについて何か新しいことを学ぶのに役立ち、コンポーネントをどのように構成することができるか:-)ですが、これが最良のアプローチであるかどうかはわかりません。ジェネリッククラスなどの名前のheadermain、およびfooter1簡単にでき、スタイルなどのコンポーネントついでに。おそらく、衝突を回避するために、より具体的な名前を使用することもできますが、カプセル化を維持するソリューションをお勧めします。
Sergiy Belozorov

あなたの懸念を理解しましたが、それがあなたの要件に対する唯一の解決策です。より具体的な名前とクラスを使用しようとすることができると述べたように、おそらくBEMアプローチを使用する
Ron

1
無効化ViewEncapsulationは、中規模または大規模なアプリケーションでは大きな問題です。それは特別な注意が必要です、またはあなたの全体のスタイリングは長い目で見ればめちゃくちゃになります。(例:総称クラス名)。そして、それが彼の要件に対する唯一の解決策であることに私は同意しません。
Dino

0

あなたはあなたのコードとscssを組み合わせることができます

まず、アプリ全体で共有するscssファイルを分離する必要があります

例えば:

style1.scss

.header { font-weight: bold }

次にstyle2.scssで

@import "style1"

または、配列のリストで定義することにより、コンポーネントコードでscssファイルのリストを組み合わせることができます

styleUrls: ['./style1.scss', './style2.scss'],
  • 注:パスをファイルパスに合わせて変更してください。これは、cssではなくscssを使用する場合にのみ機能します。

これは、角度CLIの手動の構成scssサポートです。

angular.jsonに追加

"projects": {
        "app": {
            "root": "",
            "sourceRoot": "src",
            "projectType": "application",
            "prefix": "app",
            "schematics": { // add this config
                "@schematics/angular:component": {
                    "style": "scss"
                }
            },

はい、確かにscssと@importステートメントを使用します。しかし、@ Dinoからの回答と同様に、スタイルURLをポップアップコンポーネントにハードコーディングする必要はないが、それをから読み取っPopupConfigて、実行時に何らかの方法で割り当てることができるかどうか疑問に思います。
Sergiy Belozorov

0

カスタム値であるコンポーネントにprop値を送信して、それをpopop htmlに配置できます。そして、scssファイルで特定のクラスのcssオーバーライドを追加します。したがって、カスタムコンポーネントごとに、カスタムCSSコードを使用できます。

PS:そしてはい、私は次のようなscssファイルをインポートすることをお勧めします:

@Component(
      styleUrls: ['./hero1.css'],
)

cssをjs +あなたのcssコードから分離することは、すべてのスタイリングケースを含めて、はるかに長くなる場合があります。


0

すでに述べた方法に加えて、私は探求するためにさらに2つの方法を提案します。

  1. AngularはCSSをコンポーネントにスコープし、コンポーネントの境界を越えることができるようにCSSをコンポーネントに保持したいので、Angularがそれに割り当てたスコープを見つけ、手動でスコープされたCSSを<style>ページのグローバルタグに追加します:

    @ViewChild( 'popupRef')popupRef; ngAfterViewInit(){this.popupRef.nativeElement.attributes [0] .name //これは、_ngcontent-tro-c1すべてのカスタムCSSをスコープする必要があるのと同様の値を持ちます。}

このアプローチの明らかな欠点の1つは、AngularがCSSの管理を隠しているため、管理するためにプレーンなJavaScriptを使用する必要があることです。(ここに一例

  1. この回答のようにカスタムデコレータファクトリを利用して、作成する前に@ComponentでCSSを定義してみることができます

個人的に私は2番目のオプションを検討します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.