1. 程式人生 > 其它 >ionic 示例工程(一) —— 封裝並使用 ionic 列表元件

ionic 示例工程(一) —— 封裝並使用 ionic 列表元件

技術標籤:ionicion-listionic

目錄

一.封裝基本列表元件

ths-list.component.html

ths-list.component.ts

二.封裝列表詳細資訊頁元件

list.detail.page.html

list.detail.page.ts

三.在目標專案頁面中,使用封裝好的元件(主要看這裡)

3.1 封裝好的元件使用步驟

3.2 引數說明

3.3 使用封裝元件示例

list.page.html

list.page.ts


一.封裝基本列表元件

ths-list.component.html

<!-- 下拉重新整理 -->
<!--<ion-refresher *ngIf="update" slot="fixed" (ionRefresh)="updateData($event)">-->
<!--  <ion-refresher-content pullingIcon="chevron-down" refreshingSpinner="circles">-->
<!--  </ion-refresher-content>-->
<!--</ion-refresher>-->

<ion-list>
  <!-- 遍歷 dataList, 生成列表每一項 -->
  <!-- [detail]="type === 'detail'": 行尾顯示箭頭 'detail' 為顯示箭頭,預設顯示,'favorite' 為不顯示 -->
  <!-- (click)="openDetail(item)":點選後開啟詳情頁 -->
  <ion-item
    *ngFor="let item of dataList"
    [detail]="type === 'detail'"
    (click)="openDetail(item)"
  >
    <!-- 頭像放在開始的位置, 如果存在 預設icon 或者 item 中含有 iconField 屬性, 就會顯示頭像 -->
    <ion-avatar slot="start" *ngIf="icon || item[iconField]">
      <!-- iconField 優先順序高於 icon -->
      <ion-img [src]="item[iconField] ? item[iconField] : icon"></ion-img>
    </ion-avatar>
    <!-- 列表標題 和 列表描述資訊 -->
    <ion-label>
      <!-- 列表標題 會顯示 列表項中的 titleField 屬性, 或者 -- -->
      <h3 class="title">{{ item[titleField] || "--" }}</h3>
      <!-- 列表描述資訊 , 被整合成一個 row整體, 裡面三行 -->
      <ion-row>
        <!-- [class.half-width]="desType === 'double'": 詳情顯示的樣式, 預設為 single -->
        <!-- single: 一行顯示一個詳情; double: 一行顯示兩個詳情 -->
        <!-- 遍歷描述列表, showAlias: 是否顯示中文描述, 只有傳入字串'true'時, 顯示中文描述 -->
        <span
          class="description"
          [class.half-width]="desType === 'double'"
          *ngFor="let des of desMapper">
          {{ (showAlias === "true" ? des + ":" : "") + item[des] }}
        </span>
      </ion-row>
    </ion-label>
  </ion-item>
</ion-list>

<!-- 上拉載入更多 -->
<!--<ion-infinite-scroll *ngIf="loadMore" (ionInfinite)="loadMoreData($event)">-->
<!--    <ion-infinite-scroll-content loadingSpinner="circles" loadingText="資料載入中...">-->
<!--    </ion-infinite-scroll-content>-->
<!--</ion-infinite-scroll>-->

ths-list.component.ts

/**
 * 列表元件基本邏輯
 */
export class ThsListComponent implements OnInit, DoCheck, OnChanges {
  /**
   * 上拉載入更多的滾動
   */
  @ViewChild(IonInfiniteScroll, { static: false })
  infiniteScroll: IonInfiniteScroll;

  // 列表項資料列表,是個物件組成的陣列
  public dataList: Array<object>;
  // 列表項的描述資訊,是個字串組成的陣列
  public desMapper: Array<string>;

  /**
   * 輸入資料
   */
  // 列表資料
  @Input() data: Array<object>;
  // 要在首行顯示的欄位名
  @Input() titleField: string;
  // 欄位別名(用於在列表中顯示中文的描述名稱,如:姓名:XXX 中的 姓名,同時有排序的功能)
  @Input() aliasFields: object;
  // 顯示中文描述, 預設顯示
  @Input() showAlias: string;
  // 左側顯示的圖示
  @Input() icon: string;
  // 優先順序更高的 左側顯示的圖示
  @Input() iconField: string;
  // detail:行尾顯示箭頭,預設 detail,favorite 表示不顯示箭頭
  @Input() type: "detail" | "favorite" | null = "detail";
  // 列表項對應的詳情頁地址
  @Input() detailUrl: string;
  // 描述資訊顯示格式:single 一行顯示一個 double 一行顯示兩個,預設為 single
  @Input() desType: "single" | "double" | null = "single";

  /**
   * 傳出資料
   */
  // 每個列表項的點選事件
  @Output() itemClick = new EventEmitter<object>();
  // 下拉重新整理的事件
  @Output() update = new EventEmitter<object>();
  // 上拉載入更多的事件
  @Output() loadMore = new EventEmitter<object>();

  // 檢測不同, 檢測變化
  private differ: any;

  constructor(private router: Router, private differs: KeyValueDiffers) {
    this.differ = differs.find([]).create();
  }

  ngDoCheck() {
    if (this.differ.diff(this.data)) {
      this.dataList = (this.data || []).map((item) => {
        if (this.aliasFields) {
          const mapped = Object.keys(item).map((key) => {
            const newKey = this.aliasFields[key] || key;
            return { [newKey]: item[key] };
          });
          return Object.assign({}, ...mapped);
        } else {
          return item;
        }
      });
    }
  }

  ngOnChanges(changes) {
    // 如果詳情頁展示的 欄位名 發生變化
    if (changes.aliasFields) {
        // 儲存描述資訊的陣列 就等於 詳情頁展示的欄位名所構成的陣列的鍵名 所構成的陣列
      this.desMapper = Object.keys(this.aliasFields || {}).map(
        (key) => this.aliasFields[key]
      );}
  }

  /**
   *  下拉重新整理
   */
  updateData(event) {
    this.infiniteScroll.disabled = false;
    this.update.emit(event);
  }

  /**
   * 上拉載入
   */
  loadMoreData(event) {
    this.loadMore.emit(event);
  }

  /**
   *  跳轉到詳情頁
   */
  openDetail(item: object) {
    if (this.detailUrl) {
        // 跳轉到該列表項的詳情頁, 並把該列表項傳給下一個頁面
      this.router.navigate([this.detailUrl], { queryParams: item });
    }
    this.itemClick.emit(item);
  }
  ngOnInit(): void {}
}

二.封裝列表詳細資訊頁元件

list.detail.page.html

<ion-header>
    <ion-toolbar color="primary">
        <ion-title> {{data.title}} </ion-title>
        <ion-buttons slot="start">
            <ion-back-button text=""></ion-back-button>
        </ion-buttons>
    </ion-toolbar>
</ion-header>

<ion-content>
    <ion-list>
        <!-- 遍歷鍵值列表 -->
        <ion-item *ngFor="let key of keyList">
            <!-- 排除渲染鍵值列表中的 icon選項 和 title選項 -->
            <ion-label *ngIf="key !== 'icon' && key !== 'title'">
                {{key}}: {{data[key]}}
            </ion-label>
            <!-- 如果鍵值中有 icon選項, 就把他作為圖片地址進行渲染 -->
            <ion-img [src]="data[key]" *ngIf="key === 'icon'"></ion-img>
        </ion-item>
    </ion-list>
</ion-content>

list.detail.page.ts

export class ListDetailPage implements OnInit {
  // 從上級頁面獲取的列表項資料
  public data: any;
  // 列表項資料的鍵值列表
  public keyList: string[];
  constructor(private activatedRoute: ActivatedRoute) { }

  ngOnInit(): void {
    this.activatedRoute.queryParams.subscribe(data => {
      // 獲取路由引數
      this.data = data;
      // 獲取路由引數物件中的鍵值列表
      this.keyList = Object.keys(this.data);
      // 把陣列的第一個元素刪除
      this.keyList.shift();
    });
  }
}

三.在目標專案頁面中,使用封裝好的元件(主要看這裡)

3.1 封裝好的元件使用步驟

  • 將上面一中封裝好的基本列表元件ths-list ,拷貝到目標專案的 components 資料夾中
  • 在需要使用該元件的頁面的 module.ts 檔案中,引入 ThsListModule 模組,並在 import 中宣告
  • import { ThsListModule } from '../../../../components/ths-list/ths-list.module';`
  • 在需要使用該元件的頁面的html 檔案中,使用對應標籤
  • <app-ths-list></app-ths-list>

3.2 引數說明

  • 【必填】data: {[propName: string]: string}[]:
  • 傳入的資料列表,與引數 titleField、aliasFields、iconField 一起進行欄位展示,資料列表中物件的欄位名,必須與這三個引數相匹配
> data = "[
>     {
>         title: '小明',
>         icon: 'https://ionicframework.com/docs/demos/api/list/avatar-luke.png',
>         tel: '13888888888',
>         age: '24',
>         sex: '男',
>     }, ...
> ]";
  • 【必填】titleField: string:
  • 要在首行顯示的欄位名,比如:titleField = "title",上面就是把 小明 當成首行顯示的欄位名
  • 如果寫成這樣子:titleField="2333",會顯示右下效果
  • 【選填】aliasFields: {[propName: string]: string}:
  • 要在詳情展示的欄位名的集合,與 itemClick() 事件 和 引數 showAlias 一起使用
aliasFields = "{
    sex: 'sex',
    age: '年齡',
    tel: 'tel',
}";
  • 將 sex,age,tel 這三個屬性作為詳情進行展示,('性別', '年齡', '電話') 作為中文描述在 itemClick() 事件 和 引數 showAlias 中使用
  • 【選填】iconField: string:
  • 左側展示圖片的路徑存放的欄位名,優先順序高於 引數 icon,比如:iconField = "icon",上面將 icon 屬性的值,作為圖片路徑
  • 【選填】icon: string:
  • 左側顯示的圖示,比如:icon = "https://ionicframework.com/docs/demos/api/list/avatar-yoda.png"
  • 【選填】showAlias: string:
  • 是否顯示中文描述,傳入值為 'true' 時,顯示中文描述,比如:showAlias = "true",會將描述中的 sex 改為 性別,就是換成中文了
  • 【選填】type: 'detail' | 'favorite' | null = 'detail':
  • 行尾是否顯示箭頭,'detail' 為顯示箭頭,預設顯示,'favorite' 為不顯示,比如:type = 'favorite'表示行尾不顯示箭頭
  • 【選填】detailUrl: string:
  • 點選跳轉的頁面地址,會把當前列表項 item 的資訊帶入下一頁面
  • 【選填】desType: 'single' | 'double' | null = 'single':
  • 詳情佈局顯示的方式,single 表示一行顯示一個詳情,double 表示一行顯示兩個詳情,預設為 single
  • 【選填】itemClick = new EventEmitter<object>():
  • 每個列表項的點選事件,比如:(itemClick)="openDetail($event)",$event 為當前列表項 item 的資訊
  • 每個列表項 item 打印出來的效果是這樣的:

3.3 使用封裝元件示例

  • 示例一:帶不同頭像的列表
  • 示例二:帶相同頭像的列表,因為 icon="/assets/img/wolf.png" 所以有相同頭像
  • 示例三:示例3:無頭像雙列列表,因為 desType="double" 所以兩列顯示

list.page.html

    <!-- 示例1:帶不同頭像的列表 -->
    <ths-list
      // 資料列表
      [data]="dataList1"
      // 要在首行顯示的欄位名
      titleField="title"
      // 詳情展示欄位名列表
      [aliasFields]="aliasFields1"
      // 左側顯示的頭像
      iconField="icon"
      // 是否將 詳情頁欄位名 顯示為 中文
      showAlias="true"
      // 每個資料項的 描述資訊的 展示方式
      desType="single"
      // 定義在列表基礎元件中封裝的事件 itemClick
      (itemClick)="openDetail($event)">
    </ths-list>

<!-- 示例2:帶相同頭像的列表,因為 icon="/assets/img/wolf.png" 所以有相同頭像 -->
<ths-list [data]="dataList2" titleField="title" [aliasFields]="aliasFields2" icon="/assets/img/wolf.png" showAlias="false" (itemClick)="openDetail($event)"></ths-list>

<!-- 示例3:無頭像雙列列表,因為 desType="double" 所以兩列顯示 -->
<ths-list [data]="dataList2" titleField="title" [aliasFields]="aliasFields2" desType="double" type="detail" (itemClick)="openDetail($event)"></ths-list>

list.page.ts

  // 資料列表1
  public dataList1: {[propName: string]: string}[];
  // 詳情展示列表1
  public aliasFields1: {[propName: string]: string};

  // 資料列表2 / 資料列表3
  public dataList2: {[propName: string]: string}[];
  // 詳情展示列表2 / 詳情展示列表3
  public aliasFields2: {[propName: string]: string};

  constructor(private router: Router) { }

ngOnInit(): void {

    /**
     * 示例1 資料
     */
    this.aliasFields1 = { // 資料列表每一項的詳情
      sex: 'sex',
      age: 'age',
      tel: 'tel',
    };
    this.dataList1 = [ // 資料列表項
        {
          title: '小明',
          icon: '/assets/img/xiaoming.png',
          tel: '13888888888',
          age: '24',
          sex: '男',
        }, ...
    ];

    /**
     * 示例2 / 示例3 資料
     */
    this.aliasFields2 = { // 資料列表每一項的詳情
      role: '角色',
      msg: '資訊',
    };
    this.dataList2 = [ // 資料列表項
      {
        title: '小明',
        role: '平民',
        msg: '夜晚只能睡覺'
      }, ...
    ];

  /**
   * 開啟詳情事件
   * 該方法接受列表項本身作為一個物件,並作為路由引數進行傳遞
   */
  openDetail(item: any): void { 
    this.router.navigate(['/list-detail'], {queryParams: item});
  }
}