如何将 CSS 类 应用于 AngularDart 中的另一个组件?
How to apply CSS classes to another component in AngularDart?
假设有一个显示弹出窗口的简单框架:
@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>
而无需在应用程序的根目录中定义它们?
由于您的弹出窗口不是打开它的组件的子项,因此您不能使用 ::ng-deep
我认为唯一可行的方法是从主机、弹出窗口和打开弹出窗口的组件中删除 view encapsulation(先尝试只打开弹出窗口和打开弹出窗口的组件,如果不行的话不行,把宿主的封装也去掉。)
@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 {
您可以通过将您的组件代码拆分成单独的文件来实现此目的 - 或者在您的情况下将单独的 CSS 文件。
与其直接在组件中编写样式 - styles
,不如使用 styleUrls
导入 CSS 文件。这样您就可以传递带有您的样式的文件,并且该文件可以在多个组件之间共享。
@Component(
styleUrls: ['./hero1.css', './folder/hero2.css'],
)
请记住,styleUrls 中的 URL 是相对于组件的。
使用 styleUrls
导入 css 的另一个好处是它还使您能够在该文件中使用导入。
hero1.css
@import './folder/hero2.css';
FYI: It's a common practice to split your components code into separate
files.
- hero.dart
- hero.css
- hero.html
然后在您的飞镖文件中将它们引用为:
@Component(
templateUrl: './hero.html',
styleUrls: ['./hero.css'],
)
有关此的简要信息,请参阅 AngularDart - Component Styles。
您可以将 scss 与您的代码结合使用
首先,您需要分离要在应用程序中共享的 scss 文件
例如:
在style1.scss
.header { font-weight: bold }
然后在style2.scss
@import "style1"
或者您可以通过在数组列表
中定义,在您的组件代码中组合 scss 文件列表
styleUrls: ['./style1.scss', './style2.scss'],
- 注意:请根据您的文件路径更改路径,而且这仅在您使用 scss 而不是 css
时有效
这就是您如何手动配置 scss 支持 angular cli
在angular.json中添加
"projects": {
"app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": { // add this config
"@schematics/angular:component": {
"style": "scss"
}
},
您可以将 prop 值发送到组件,可以自定义 class 并将其放入您的 popop html。然后在 scss 文件中为特定 class 添加额外的 css 覆盖。因此,对于每个自定义组件,您都可以拥有自定义 css 代码。
PS:是的,我建议导入 scss 文件,例如:
@Component(
styleUrls: ['./hero1.css'],
)
最好将 css 与 js + 您的 css 代码分开,这样可以更长,包含所有样式案例。
除了已经提到的方法之外,我还建议您探索另外两个途径:
因为 Angular 范围 CSS 到组件,我们希望保持这种方式,您可以通过找出范围 Angular 分配给它并手动将范围 CSS 添加到页面上的全局 <style>
标记中:
@ViewChild('popupRef') popupRef;
ngAfterViewInit() {
this.popupRef.nativeElement.attributes[0].name // 这将有一个类似于 _ngcontent-tro-c1
的值,您需要用它来限定所有自定义 CSS 的范围。
}
这种方法的一个明显缺点是 Angular 隐藏了 CSS 管理,因此您必须求助于纯 JS 来管理它。 ()
- 您可以尝试在使用自定义装饰器工厂
创建之前在 @Component 中定义 CSS
就我个人而言,我会探索第二个选项,因为它似乎不那么骇人听闻
假设有一个显示弹出窗口的简单框架:
@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>
而无需在应用程序的根目录中定义它们?
由于您的弹出窗口不是打开它的组件的子项,因此您不能使用 ::ng-deep
我认为唯一可行的方法是从主机、弹出窗口和打开弹出窗口的组件中删除 view encapsulation(先尝试只打开弹出窗口和打开弹出窗口的组件,如果不行的话不行,把宿主的封装也去掉。)
@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 {
您可以通过将您的组件代码拆分成单独的文件来实现此目的 - 或者在您的情况下将单独的 CSS 文件。
与其直接在组件中编写样式 - styles
,不如使用 styleUrls
导入 CSS 文件。这样您就可以传递带有您的样式的文件,并且该文件可以在多个组件之间共享。
@Component(
styleUrls: ['./hero1.css', './folder/hero2.css'],
)
请记住,styleUrls 中的 URL 是相对于组件的。
使用 styleUrls
导入 css 的另一个好处是它还使您能够在该文件中使用导入。
hero1.css
@import './folder/hero2.css';
FYI: It's a common practice to split your components code into separate files.
- hero.dart
- hero.css
- hero.html
然后在您的飞镖文件中将它们引用为:
@Component(
templateUrl: './hero.html',
styleUrls: ['./hero.css'],
)
有关此的简要信息,请参阅 AngularDart - Component Styles。
您可以将 scss 与您的代码结合使用
首先,您需要分离要在应用程序中共享的 scss 文件
例如:
在style1.scss
.header { font-weight: bold }
然后在style2.scss
@import "style1"
或者您可以通过在数组列表
中定义,在您的组件代码中组合 scss 文件列表styleUrls: ['./style1.scss', './style2.scss'],
- 注意:请根据您的文件路径更改路径,而且这仅在您使用 scss 而不是 css 时有效
这就是您如何手动配置 scss 支持 angular cli
在angular.json中添加
"projects": {
"app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": { // add this config
"@schematics/angular:component": {
"style": "scss"
}
},
您可以将 prop 值发送到组件,可以自定义 class 并将其放入您的 popop html。然后在 scss 文件中为特定 class 添加额外的 css 覆盖。因此,对于每个自定义组件,您都可以拥有自定义 css 代码。
PS:是的,我建议导入 scss 文件,例如:
@Component(
styleUrls: ['./hero1.css'],
)
最好将 css 与 js + 您的 css 代码分开,这样可以更长,包含所有样式案例。
除了已经提到的方法之外,我还建议您探索另外两个途径:
因为 Angular 范围 CSS 到组件,我们希望保持这种方式,您可以通过找出范围 Angular 分配给它并手动将范围 CSS 添加到页面上的全局
<style>
标记中:@ViewChild('popupRef') popupRef; ngAfterViewInit() { this.popupRef.nativeElement.attributes[0].name // 这将有一个类似于
_ngcontent-tro-c1
的值,您需要用它来限定所有自定义 CSS 的范围。 }
这种方法的一个明显缺点是 Angular 隐藏了 CSS 管理,因此您必须求助于纯 JS 来管理它。 (
- 您可以尝试在使用自定义装饰器工厂
就我个人而言,我会探索第二个选项,因为它似乎不那么骇人听闻