angular 生命週期鉤子 ngOnInit() 和 ngAfterViewInit() 的區別

angular 生命週期鉤子的詳細介紹在 https://angular.cn/guide/lifecycle-hooks  文檔中作了介紹。css

ngOnInit() 在 Angular 第一次顯示數據綁定和設置指令/組件的輸入屬性以後,初始化指令/組件;bootstrap

ngAfterViewInit() 初始化完組件視圖及其子視圖以後調用。app

ngOnInit() 鉤子應該是咱們用得最頻繁的一個了,在使用命令 ng g component <component-name> 生成一個組件後,就有 ngOnInit() 方法。ide

ngOnInit() 鉤子能夠做爲初始化時調用一些方法。如:ui

ngOnInit() 鉤子也能夠更改視圖樣式,如:this

建議在寫 angular 的時候儘可能少的使用 jQuery,除非一些簡單好用的 jQuery 插件spa

而 ngAfterViewInit() 鉤子是在組件視圖或者子組件視圖初始化完成以後調用。插件

 

項目中遇到了這樣一個需求:code

1、描述:component

1. 經過選擇開始時間和結束時間,來查詢列表記錄:

2. 這個功能在一個模塊,4個不一樣的組件中用到;

3. 初始化時開始時間是當前時間減1天,結束時間是當前時間;

4. 開始時間和結束時間格式「2018-12-03 09:09:09」;

2、解決方法:

1. 時間控件選擇了日期時間選擇器(Bootstrap日期和時間表單組件) 

2. 將日期時間選擇器功能進行封裝成一個單獨的組件 DateTimeSelectorComponent,方便4個組件中用到;

3. 以其中一個父組件 OfflineComponent 爲例,監聽子組件 DateTimeSelectorComponent 的事件,子組件暴露一個 EventEmitter  屬性,當事件發生時,子組件利用該屬性 emits(向上彈射)事件。父組件綁定到這個事件屬性,並在事件發生時做出迴應

4. 待子組件返回值了,父組件才作出相應的數據請求和方法調用。這裏父組件中就是用 ngAfterViewInit() 鉤子

3、最終結果:

3、實際操做:

1. 首先封裝 DateTimeSelectorComponent 組件

  • 模板: 
<div class="start-end-time-search">
  <label for="startTime" class="start-time-label">起止時間</label>
  <input type="text" [(ngModel)]="startTime" placeholder="請選擇開始時間" readonly id="startTime" class="start-time">
  <label for="endTime" class="end-time-label"></label>
  <input type="text" [(ngModel)]="endTime" placeholder="請選擇結束時間" readonly id="endTime" class="end-time">
</div>
  • 組件

    1.暴露一個 EventEmitter 屬性,以及定義一些須要返回給父組件的屬性

  public startTime: string = "";
  public endTime: string = ""; 
  public isEnabledSearchBtn: boolean = true;  // 查詢按鈕是可用的
  public startTimeErrorTip: string = ""; // 開始時間選擇錯誤提示
  public endTimeErrorTip: string = ""; // 結束時間選擇錯誤提示
  @Output() timeInfo = new EventEmitter<object>();

    2. 定義一個方法來格式化日期時間

// 日期時間格式 "2018-09-20 00:00:00"
  dateTimeFormat(dateTime) {
    let dateTimeObj = {
      "year": dateTime.getFullYear(),
      "month": dateTime.getMonth() + 1,
      "day": dateTime.getDate(),
      "hours": dateTime.getHours(),
      "minutes": dateTime.getMinutes(),
      "seconds": dateTime.getSeconds()
    };
    for (let k in dateTimeObj) {
      if (dateTimeObj[k] < 10) {
        dateTimeObj[k] = "0" + dateTimeObj[k];
      }
    }
    let dateTimeString = dateTimeObj.year + "-" + dateTimeObj.month + "-" + dateTimeObj.day + " "
      + dateTimeObj.hours + ":" + dateTimeObj.minutes + ":" + dateTimeObj.seconds;
    return {"obj": dateTimeObj, "string": dateTimeString};
  }

返回兩種類型,對象類型和字符串類型可供選擇。

    3. 將信息返回給父組件

  // 選擇時間,選擇完時間或者初始化時,調用一次,將時間信息發送給父組件
  selectTime() {
    let data = {
      isEnabledSearchBtn: this.isEnabledSearchBtn,
      startTime: this.startTime,
      endTime: this.endTime,
      startTimeErrorTip: this.startTimeErrorTip,
      endTimeErrorTip: this.endTimeErrorTip
    };
    this.timeInfo.emit(data);
  }

    4. 組裝數據(返回給父組件的信息)

ngOnInit() {
  let initNowTime = this.dateTimeFormat(new Date());
  // 開始時間用當前時間減去一天,結束時間使用當前時間
  this.startTime = initNowTime.obj.year + "-" + initNowTime.obj.month + "-" +
    ((initNowTime.obj.day - 1) < 10 ? ("0" + (initNowTime.obj.day - 1)) : (initNowTime.obj.day - 1)) + " " +
    initNowTime.obj.hours + ":" + initNowTime.obj.minutes + ":" + initNowTime.obj.seconds;

  this.endTime = initNowTime.string;

  this.selectTime();  // 初始化的時候調用一次使得「初始化完組件視圖及其子視圖以後」 startTime 和 endTime 有值

  /*下面處理選擇的時間*/
  let jQuery: any = $;
  let that = this;
  jQuery("#startTime").datetimepicker({
    autoclose: true,
    format: "yyyy-mm-dd hh:ii:ss",
    minuteStep: 1,
    language: "zh-CN",
    todayBtn: "linked",
    todayHighlight: true,
    endDate: (new Date),
    zIndexOffset: 1000
  }).on("changeDate",function(startTime) {
    that.startTime = that.dateTimeFormat(startTime.date).string;
    if (Date.parse(that.endTime) - Date.parse(that.startTime) > 31536000000) {  // 31536000000 是一年的時間戳
      that.startTimeErrorTip = that.endTimeErrorTip == "時間跨度不能大於一年" ? "" : "時間跨度應小於一年";
      that.isEnabledSearchBtn = false;
    } else if (that.startTime > that.endTime) {
      that.startTimeErrorTip = that.endTimeErrorTip == "結束時間不能小於開始時間" ? "" : "開始時間不能大於結束時間";
      that.isEnabledSearchBtn = false;
    } else {
      that.startTimeErrorTip = "";
      that.endTimeErrorTip = "";
      that.isEnabledSearchBtn = true;
    }

    that.selectTime();
  }).data('datetimepicker');

  jQuery("#endTime").datetimepicker({
    autoclose: true,
    format: "yyyy-mm-dd hh:ii:ss",
    minuteStep: 1,
    language: "zh-CN",
    todayBtn: "linked",
    todayHighlight: true,
    endDate: (new Date),
    zIndexOffset: 1000
  }).on("changeDate", function(endTime) {
    that.endTime = that.dateTimeFormat(endTime.date).string;
    if (Date.parse(that.endTime) - Date.parse(that.startTime) > 31536000000) {  // 31536000000 是一年的時間戳
      that.endTimeErrorTip = that.startTimeErrorTip == "時間跨度應小於一年" ? "" : "時間跨度不能大於一年";
      that.isEnabledSearchBtn = false;
    } else if (that.startTime > that.endTime) {
      that.endTimeErrorTip = that.startTimeErrorTip == "開始時間不能大於結束時間" ? "" : "結束時間不能小於開始時間";
      that.isEnabledSearchBtn = false;
    } else {
      that.startTimeErrorTip = "";
      that.endTimeErrorTip = "";
      that.isEnabledSearchBtn = true;
    }

    that.selectTime();
  }).data('datetimepicker');
}

2. 父組件中使用子組件

  • 模板
<app-date-time-selector (timeInfo)="handle($event)"></app-date-time-selector>

父組件綁定的事件屬性同子組件中 EventEmitter 屬性名稱同樣

  • 組件
  // 時間選擇器操做事件
  handle(value) {
    this.startTimeErrorTip = value.startTimeErrorTip;
    this.endTimeErrorTip = value.endTimeErrorTip;
    this.startTime = value.startTime;
    this.endTime = value.endTime;
    this.isEnabledSearchBtn = value.isEnabledSearchBtn;
  }

  ngOnInit() { }

  ngAfterViewInit() {this.offlineRecordList();
  }

父組件接收到子組件返回的信息保存在 value 對象中,分別拆分給相應的屬性。

最後,當父組件視圖和子組件視圖完成初始化後,再調用方法,來獲取列表數據。

相關文章
相關標籤/搜索