Làm cách nào để áp dụng các lớp CSS cho một thành phần khác trong AngularDart?


8

Giả sử có một khung đơn giản để hiển thị cửa sổ bật lên:

@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);
}

Điều này sau đó có thể được sử dụng như thế này:

// 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);
  }
}
...

Có cách nào để chuyển tiếp các kiểu từ <some-other-component>đến <happy-popup>mà không phải xác định chúng ở gốc của ứng dụng không?

Câu trả lời:


5

Bạn có thể đạt được điều này bằng cách chia mã thành phần của bạn thành các tệp riêng biệt - hoặc tệp CSS riêng trong trường hợp của bạn.

Thay vì viết kiểu thẳng trong thành phần - styles, bạn sẽ nhập tệp CSS bằng cách sử dụng styleUrls. Bằng cách đó, bạn có thể truyền (các) tệp với kiểu của mình và tệp có thể được chia sẻ giữa nhiều thành phần.

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

Hãy nhớ rằng các URL trong styleUrls có liên quan đến thành phần.

Một lợi ích khác của việc nhập css styleUrlslà nó cũng cấp cho bạn khả năng sử dụng nhập trong tệp đó.

anh hùng1.css

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

FYI: Đó là một cách phổ biến để chia mã thành phần của bạn thành các tệp riêng biệt.

  • anh hùng
  • anh hùng.css
  • anh hùng.html

Và sau đó trong tệp phi tiêu của bạn tham chiếu chúng như:

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

Vui lòng tham khảo AngularDart - Kiểu thành phần để biết thông tin ngắn gọn về điều này.


Cảm ơn bạn. Tôi đã nhận thức được thực tế rằng tôi có thể tách các bảng định kiểu thành một tệp riêng biệt, nhưng tôi không nghĩ đến việc sử dụng lại chúng trên nhiều thành phần. Tôi không chắc liệu giải pháp này có đủ phổ biến hay không, ví dụ, một thành phần bật lên có thể là một phần của khung và việc nhập các phần của ứng dụng vào khung có thể trái với thông lệ phần mềm tốt. Lý tưởng nhất, khung sẽ cung cấp một cách để nhập tệp css tùy ý được cung cấp qua PopupConfig. Có thể tùy chỉnh thuộc styleUrlstính trên một thành phần trong thời gian chạy không?
Sergiy Belozorov

Ngoài ra, nếu có nhiều thành phần muốn mở cùng một cửa sổ bật lên, nhưng phong cách nó khác nhau thì sao?
Sergiy Belozorov

1
Có, bạn có thể thiết lập styleUrlsđộng tại thời gian chạy. Có nhiều cách để làm điều đó. Tôi đề nghị bạn tìm kiếm Angular dynamic styleUrlsđể có được một số ý tưởng và xem cái nào phù hợp với bạn nhất. Về câu hỏi thứ hai. Nếu đó là trường hợp, tôi sẽ nhập tệp kiểu dáng cửa sổ bật lên được chia sẻ + tệp kiểu mà tôi ghi đè lên kiểu tôi muốn thay đổi cho một thành phần cụ thể.
Dino

Tôi không chắc chắn tôi hiểu đề xuất của bạn về cách tạo kiểu cho hai cửa sổ bật lên khác nhau. Cả hai cửa sổ bật lên sẽ sử dụng cùng một thành phần, vì vậy cách duy nhất tôi có thể ghi đè lên các kiểu từ một tệp được chia sẻ là bằng cách nối thêm một mục mới vào styleUrlsthời gian chạy, phải không? Điều gì sẽ xảy ra nếu hai cửa sổ bật lên xuất hiện cùng một lúc, ví dụ: một cửa sổ mở khác và cần được tạo kiểu khác nhau? Nếu tôi sửa đổi styleUrls, nó sẽ không theo cả hai? Cuối cùng, tôi không thể tìm thấy một bài viết hay về cách sửa đổi linh hoạt styleUrlsmà không cần hack. Nó dường như không được hỗ trợ bởi Angular nitive.
Sergiy Belozorov

1

Vì cửa sổ bật lên của bạn không phải là con của thành phần đã mở nên bạn không thể sử dụng :: ng-deep

Điều duy nhất tôi nghĩ sẽ hoạt động là loại bỏ đóng gói chế độ xem khỏi máy chủ, cửa sổ bật lên và thành phần mở cửa sổ bật lên (chỉ thử cửa sổ bật lên và thành phần mở cửa sổ bật lên trước, nếu không hoạt động, hãy xóa đóng gói của máy chủ lưu trữ cũng.)

@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 {

Bạn có thể vui lòng giải thích những gì bạn có nghĩa là "loại bỏ đóng gói xem"?
Sergiy Belozorov

@SergiyBelozorov Xong :). hãy cho tôi biết nếu nó giúp bạn
Ron

Nó chắc chắn đã giúp tôi tìm hiểu một cái gì đó mới về Angular và cách người ta có thể định cấu hình các thành phần :-), nhưng tôi không chắc đây là cách tiếp cận tốt nhất. Với tên lớp generic như header, mainfooterngười ta có thể dễ dàng theo phong cách các thành phần như tình cờ. Có lẽ người ta có thể cố gắng sử dụng các tên cụ thể hơn để tránh xung đột, nhưng tôi thích một giải pháp giữ cho việc đóng gói.
Sergiy Belozorov

Tôi hiểu mối quan tâm của bạn nhưng đó là giải pháp duy nhất cho yêu cầu của bạn. Như bạn đã nói, người ta có thể thử sử dụng tên và các lớp cụ thể hơn, có thể sử dụng phương pháp BEM
Ron

1
Vô hiệu hóa ViewEncapsulationlà một không lớn đối với các ứng dụng cỡ trung hoặc lớn. Nó được chăm sóc đặc biệt hoặc toàn bộ kiểu dáng của bạn sẽ bị rối tung trong một thời gian dài. (ví dụ: tên lớp chung). Và tôi không đồng ý rằng đó là giải pháp duy nhất cho yêu cầu của anh ấy.
Dino

0

Bạn có thể kết hợp scss với mã của bạn

Trước tiên, bạn cần tách riêng tệp scss mà bạn muốn chia sẻ trên ứng dụng

Ví dụ:

Trong style1.scss

.header { font-weight: bold }

Sau đó, trong style2.scss

@import "style1"

Hoặc bạn có thể kết hợp danh sách tệp scss trong mã thành phần của mình bằng cách xác định trong danh sách mảng

styleUrls: ['./style1.scss', './style2.scss'],
  • Lưu ý: Vui lòng thay đổi đường dẫn theo đường dẫn tệp của bạn và điều này chỉ hoạt động khi bạn sử dụng scss chứ không phải css

Đây là cách bạn có thể thủ công cấu hình scss hỗ trợ cho cli góc

Trong angular.json thêm

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

Vâng, chúng tôi thực sự sử dụng scss và @importtuyên bố. Nhưng giống như câu trả lời từ @Dino, tôi tự hỏi liệu có thể không phải mã hóa URL kiểu vào thành phần bật lên, nhưng đọc nó từ PopupConfigvà bằng cách nào đó gán nó vào thời gian chạy không?
Sergiy Belozorov

0

Bạn có thể gửi giá trị prop đến thành phần, có thể là lớp tùy chỉnh và đặt nó trong html popop của bạn. Và sau đó trong tập tin scss thêm ghi đè css cho lớp cụ thể. Vì vậy, đối với mỗi thành phần tùy chỉnh, bạn có thể có mã css tùy chỉnh.

PS: Và vâng, tôi sẽ đề nghị nhập tệp scss như:

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

Nó chỉ tốt hơn để tách css từ js + mã css của bạn sau đó có thể dài hơn nhiều, chứa tất cả các trường hợp kiểu dáng.


0

Ngoài các phương pháp đã được đề cập, tôi sẽ đề xuất thêm hai con đường để khám phá:

  1. vì Angular phạm vi CSS cho các thành phần và chúng tôi muốn giữ nó theo cách này mà ranh giới thành phần chéo của bạn có thể được thực hiện bằng cách tìm hiểu phạm vi mà Angular gán cho nó và thêm CSS phạm vi thủ công vào <style>thẻ toàn cầu trên trang:

    @ViewChild ('popupRef') popupRef; ngAfterViewInit () {this.popupRef.nativeEuity.attribut [0] .name // cái này sẽ có một giá trị tương tự _ngcontent-tro-c1mà bạn sẽ cần để phạm vi tất cả CSS tùy chỉnh của bạn với. }

Một nhược điểm rõ ràng của cách tiếp cận này là Angular che giấu việc quản lý CSS và do đó bạn sẽ phải dùng đến JS đơn giản để quản lý nó. ( một ví dụ ở đây )

  1. bạn có thể thử xác định CSS trong @Component trước khi tạo nó bằng cách sử dụng nhà máy trang trí tùy chỉnh như trong câu trả lời này

Cá nhân tôi sẽ khám phá tùy chọn thứ hai vì nó có vẻ ít hack hơn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.