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

测试中的数据显示:

猜你喜欢

转载自blog.csdn.net/ColourfulTiger/article/details/83341432