1. 程式人生 > >ionic3+angular4元件通訊,1元件解決2需求

ionic3+angular4元件通訊,1元件解決2需求

之前一直想不明白元件的複用性該怎樣提高,總覺得一個元件就只能用一次,但經過這幾天的折騰,終於開竅了,成功的將一個元件封裝成滿足2個需求的框框了。

先簡單介紹一下,這個案例大概是做什麼的。本案例是以投票為需求展開的,滿足的內容是一個元件不僅要能顯示列表所有內容,還能滿足搜尋功能,能根據某一關鍵字搜尋到具體的人。

程式碼中最主要的是兩個部分,一個是子元件封裝,還有一個是父元件呼叫並傳遞相關資訊,具體內容可以見下面的程式碼,有一些內容是補充的知識點,以及本文涉及的知識點。

具體程式碼可見:https://download.csdn.net/download/colourfultiger/10776253

效果圖:

1、先看子元件:

  (1)html部分,這一部分也有一定的引數判斷在裡面,因為angular.js沒有if-else結構,僅有if,所以我涉及了一個開關控制量用來控制具體什麼情況來展示什麼內容,儘可能的發揮if的用處,當然,這是限制在需求不多的情況下,如若需求比較大,是不推薦使用這種方式的。

    關鍵點講解:

    onoff:作為一個開關,為true時執行展示所有參賽選手的資訊。false時執行查詢後展示的單個資訊。

    datas:兩個迴圈體用一個裝資料的容器,當然也會有弊端,可以結合具體情況具體解決。這裡講資料放置在datas中。

    searchKey:是用來接收來自父元件傳來的資訊,是一個搜尋值,後面內容根據這個值來展示該展示的內容。


<div class="adsBox">
  <div class="adsHead">
    <span>當前參選選手:{{searchKey}}</span>
    <!--<span><label>你參與的投票數為:</label>{{joinBill}}</span>-->
    <ion-icon name="arrow-forward" color="primary" style="float: right;margin-right:7%;margin-top: 2%;"></ion-icon>
  </div>
  <br/>
    <div class="adsContent" *ngIf="onoff===true">
      <div *ngFor="let item of datas,let i = index;" class="voteBox">
        <div class="imgBox">
          <img src="{{item.src}}" style="width: 50px; height: 50px;"/>
        </div>
        <p><label>選手:</label><a>{{item.player}}</a></p>
        <p><label>票數:</label><a>{{item.bills}}</a></p>
        <button class="vote" ngClass="{{item.style}}" (click)="voteBills(i,datas)">{{item.tips}}</button>
      </div>
    </div>
    <div class="adsContent" *ngIf="onoff===false">
      <div *ngFor="let item of datas,let i = index;" class="voteBox">
        <div *ngIf="item.id==searchKey">
          <div class="imgBox">
            <img src="{{item.src}}" style="width: 50px; height: 50px;"/>
          </div>
          <p><label>選手:</label><a>{{item.player}}</a></p>
          <p><label>票數:</label><a>{{item.bills}}</a></p>
          <button class="vote" ngClass="{{item.style}}" (click)="voteBills(i,searchTests)">{{item.tips}}</button>
        </div>
      </div>
    </div>

</div>

scss部分

簡單地封裝了一些樣式,如投票按鈕的選中與否等等。

page-ads-card {
  $borderColor:#eaeaea;
  $voting:#1a8bd4;
  $voted: #fb3c34;
  $btnhover: #3063cc;
  .adsHead {
    width: 100%;
    background: #f1f1f1;
    margin-bottom: 10px;
    span{
      color: #999999;
      font-weight: bolder;
      -webkit-font-smoothing: antialiased;
    }
  }
  div {
    display: inline-block;
    span{
      display: inline-block;
      margin:8px 35px;
      font-size: 16px;
      color: #999999;
    }
  }
  .adsBox{
    width: 100%;
    display: block;
    height: auto;
    //height: 200px;
    background:#fbfbfb;
    border-top: 1px solid $borderColor;
    border-bottom: 1px solid $borderColor;
  }
  //投票盒子
  .adsContent {
    width: 100%;
    margin: 0 auto;
  }
  .imgBox {
    margin: 0 auto;
  }
  .voteBox {
    width: 33.3%;
    text-align: center;
    margin:5px 0px;
  }
  //投票按鈕
  .vote {
    padding: 5px 8px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    color: white;
  }
  .voting {
    @extend .vote;
    background: $voting;
  }
  .voted {
    @extend .vote;
    background: $voted;
  }
}

ts部分,關鍵部分,父元件也是通過呼叫子元件的方法來改變子元件的某些值

export class AdsCardPage {

  @Input() searchKey: number;
  @Input() operation: boolean;
  // datas: any = [];   //裝選手資料資訊
  joinBill: number;
  onoff: boolean;
  datas: Object = null;  //接收本地資料的容器
  searchTests: Object = [];
  searchTest: Array<{ player: string, bills: number, checked: boolean, style: string, tips: string }>;//接收搜尋後儲存的資料
  constructor(public navCtrl: NavController,
              public navParams: NavParams,
              private ref: ChangeDetectorRef,
              private  voteService: VoteService) {

    this.getVoteInfo();
    this.joinBill = 0;
    this.onoff = true;

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad AdsCardPage');


  }

  //獲取資料
  getVoteInfo() {
    this.voteService.getRequestContent()
      .subscribe(res => {
        this.datas = res.json();
        console.log("listData----->", this.datas);

        this.ref.detectChanges();
      }, error => {
        console.log(error);
      });
  }

  //參與投票
  public voteBills(item) {
    //1、投票  改變按鈕顏色為投票  票數增加  改變為已投狀態  並儲存到對應的json中
    //2、棄票  改變按鈕顏色為棄票  票數減少  改變為未投狀態  並儲存到對應的json中

    if (this.datas[item].checked) {
      if (this.joinNum(this.joinBill)) {
        this.datas[item].bills++;
        this.datas[item].style = "voted";
        this.datas[item].checked = false;
        this.datas[item].tips = "已投票";
        this.joinBill++;
      }
    } else {
      this.datas[item].bills--;
      this.datas[item].style = "voting";
      this.datas[item].checked = true;
      this.datas[item].tips = "投他一票";
      this.joinBill--;
    }

  }

  //判斷當前投票數是否超過 1 個
  public joinNum(num: number) {
    if (num >= 1) {
      return false;
    } else {
      return true;
    }
  }


  //search方法
  public searchStu(id: number) {
    this.onoff = false;
    this.voteService.getRequestContent()
      .subscribe(res => {
        console.log(res);
        console.log(res.json());
        var num = res.json().length;
        let j = 0;
        for (var i = 0; i < num; i++) {
          if (res.json()[i].id == id) {
            /* 清空原來的資料*/
            this.datas = [];
            /*將獲取的資料儲存在一個乾淨的容器中*/
            this.datas[j] = res.json()[i];
            /*列印這個相同的值*/
            console.log(res.json()[i].id);
            /*若有重複的繼續賦值給原來的變數*/
            j++;
            /*列印這個資料在陣列中的位置*/
            console.log(j);
            console.log(this.datas);
          }
        }
        this.ref.detectChanges();
      }, error => {
        console.log(error);
      });
  }


}

該部分涉及到通訊方式,以及獲取資料的方式。

2、父元件的內容如下:

  html部分

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      查詢選手
    </ion-title>
    <!--<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>-->
    <ion-searchbar (ionInput)="child.searchStu(studentId)" [(ngModel)]="studentId"></ion-searchbar>
  </ion-navbar>
</ion-header>
<ion-content>
  <div>parent元件</div>

  <!--思路:
        searchKey:要查詢的資料
        operation:實際要進行的操作
  -->
  <page-ads-card
    #child
    [searchKey]="studentId"
    [operation]="search" >
  </page-ads-card>
</ion-content>

這裡需要注意的是父元件繫結子元件方法的方式:

通過在子元件上加一個#child,然後在通過child.xxx()方法來使用子元件中的方法。

scss部分;

page-contact {
  .searchbar-input-container{
    //width: 60%;
    //-webkit-border-radius: 40px;
    //-moz-border-radius: 40px;
    //border-radius: 40px;
  }
  ion-title{
   flex: 0;
  }
  .toolbar-content-md{
    display: inline-flex;
  }
  ion-searchbar{
    position: relative;
    display: inline-block;
    align-items: center;
    width: 60%;
    float: right;
  }
  .searchbar-md .searchbar-input {
    -webkit-border-radius: 30px;
    -moz-border-radius: 30px;
    border-radius: 30px;
    padding: 0px 40px;
  }
  .searchbar-md .searchbar-search-icon {
    top: 8px;
  }
}

ts部分,非常簡潔

@Component({
  selector: 'page-contact',
  templateUrl: 'contact.html'
})
export class ContactPage {

  studentId:number;   //1、該變數用來儲存需要搜尋的學號資訊
  search:boolean=false;  //開啟搜尋許可權
  constructor(public navCtrl: NavController) {

  }

3、通訊的方法

本案例採用的是重建一個service檔案,然後對這個檔案註冊之類的就可以使用了。

import {Injectable} from '@angular/core';
import {Observable} from "rxjs/observable";
import  {Http,Response} from "@angular/http";
import "rxjs/add/operator/map"

@Injectable()
export class VoteService {

  constructor(private httpService: Http) {

  }

  //網路介面請求資料
  getHomeInfo():Observable<Response> {
    return this.httpService.request("");
  }

  //本地json檔案請求
  getRequestContent(){
    return this.httpService.get("assets/json/votemember.json");
  }
}

測試中的資料顯示: