首页 文章

如何在不破坏封装的情况下调用子组件方法?

提问于
浏览
1

我有基于供应商组件的自定义日期和时间选择器组件 . 如果简化它可以看起来如此:

@Component({
  selector: 'app-date-time-picker',
  template: `
    <vendor-date-picker [(ngModel)]="date"></vendor-date-picker>
    <vendor-time-picker [(ngModel)]="time"></vendor-time-picker>
  `
})
export class DateTimePickerComponent {
  @Output() timestampChanged = new EventEmitter<number>();

  date: string;
  time: string;

  reset() {
    this.date = "";
    this.time = "";
  }
}

我有一个使用DateTimePicker的父组件,有时需要重置它状态:

@Component({
  selector: 'app-parent',
  template: `
    <app-date-time-picker #dateTimePicker (timestampChanged)="updateDateTime($event)"></app-date-time-picker>
  `
})
export class Parent {
  @ViewChild('dateTimePicker') private _dateTimePicker: DateTimePickerComponent;

  someEvent() {
    this._dateTimePicker.reset();
  }
}

我从供应商那里创建这样丑陋组件的原因(和相关代码)超出了问题的范围 . 对我来说重要的是使用ViewChild打破了对孩子的封装 . 而且我无法使用“私人”关键字来保护其他子字段,例如“日期”和“时间”,因为它们在模板中使用 . 所以问题是角度是否拥有通过某些声明的公共接口(如使用输入)调用子方法或者保护其他子组件字段仍然可以在模板中使用但不能在外部访问的机制?

1 回答

  • 1

    父组件不会破坏 DateTimePickerComponent 封装 - 只要 reset 方法被视为公共方法 . 组件只是类实例,父组件可以访问其公共成员 .

    考虑到父和子都是第一方组件,通常没有实际的封装问题,因为开发人员通常知道组件的预期用途,但这可能是更大团队的问题 .

    据我所知,这里的问题是由于Angular AOT编译的工作方式,它在编译模板中提供了类型安全性,但要求组件模板中使用的所有组件成员都是 public - 而组件模板和类可以被视为单个开发商实体,这些成员实际上是私人的 .

    一种选择是使用匈牙利表示法并为事实上私有的所有组件成员加上下划线(这提供certain benefits,尽管Angular opinionated style guide状态) - 包括组件模板中使用的那些 . 缺点是由于大量的强调属性,模板的可读性降低 . 另一个缺点是,这种方式不应该在模板中使用(例如大多数注入的服务) .

    另一种选择是提供预期具有相应公共接口的公共成员的组件:

    interface IDateTimePickerComponent {
      reset();
    }
    
    export class DateTimePickerComponent implements IDateTimePickerComponent {
      @Output() timestampChanged = new EventEmitter<number>();
    
      date: string;
      time: string;
    
      reset() {
        this.date = "";
        this.time = "";
      }
    }
    

    使用如下:

    @ViewChild('dateTimePicker') private _dateTimePicker: IDateTimePickerComponent;
    

    当然,还有其他的component interaction options,但是由于封装问题,它们不应该是首选的 . OOP原则的存在是为了指导和帮助开发人员,而不是跳过箍 .

相关问题