Angular进阶(二)——通过实例深入理解组件通信

前言

Angular2的核心理念是组件,组件可以让我们的代码更加整洁,通过父子之间的传值可以节省更多代码量,下面我们就深入介绍一下

内容

组件的基本组成

这里写图片描述

必备元素:

  • 装饰器(@Component)
  • 模板(Template)
  • 控制器 (Controller)

可选注入对象

  • 输入属性(@Input)
  • 提供器(Providers)
  • 声明周期钩子(Lifecycle Hooks)

可选的输出对象

  • 样式表(styles)
  • 动画(Animations)
  • 输出属性(@Outputs)

组件实践篇

这里写图片描述
这个效果页面包括了两部分:tab页和表格,按照正常的思路,我们将他们写在同样一个组件内部,肯定会发生代码冗余,因为会写两次table的html页面,为了简化代码,得到对table的复用,必须引入组件的理念。

子组件table的封装

1.模板页面


<div class="container">
<table id="table" class="table" style="width: 80%;margin-left: 5%" >
  <thead>
  <tr style="text-align: center">
    <td colspan="6">
      <div class="btn-tr">
      <button id="btn_add" type="button" class="btn btn-primary" (click)="createEvaluationPaper()">
      <span class="fa fa-plus" aria-hidden="true"></span>新增问卷</button>
        <input class="form-control"  (keypress) = "querykey($event,info.value)"  style="display: inline;width: 50%" #info placeholder="请输入问卷名称">
        <span><i class="fa fa-search" (click)="query(info.value)"></i></span>
      </div>
    </td>
  </tr>
    <tr>
      <th hidden >课程属性id</th>
      <th hidden>试卷id</th>
      <th width="250px" >试卷名称</th>
      <th width="100px" >试卷分数</th>
      <th width="100px" >试卷状态</th>
      <th width="250px">操作</th>
    </tr>
  </thead>
    <tbody  *ngFor="let q of questionaires;let i=index">
       <tr *ngIf="i>=(page-1)*pageSize && i<page*pageSize">
         <th style="display: none">{{q.coursePropertyId}}</th>
         <th  hidden>{{q.id}}</th>
           <th>{{q.name}}</th>
           <th>{{q.score}}</th>
           <!--对试卷的状态进行判断-->
           <th [ngSwitch]="q.status">
             <span *ngSwitchCase="0">草稿</span>
             <span *ngSwitchCase="1">运行</span>
             <span *ngSwitchCase="2">暂停</span>
           </th>

           <--操作按钮:状态编辑,编辑问卷,删除问卷-->
          <th style="cursor:pointer;" [ngSwitch]="q.status">
            <a href="javascript:;" title="点击发布" #aoper (click)="oper(q,aoper)" *ngSwitchCase="0"><i class="fa fa-play"></i></a>
            <a href="javascript:;" title="点击运行" #boper (click)="oper(q,boper)" *ngSwitchCase="2"><i class="fa fa-play"></i></a>
            <a href="javascript:;" title="点击停止" #coper (click)="oper(q,coper)" *ngSwitchCase="1"><i class="fa fa-stop"></i></a>
            <a href='javascript:;' style="color: green" (click)="analysis(q)"><span class='fa fa-signal'></span></a>
            <a href='javascript:;' style="color: deepskyblue" (click)="btnEdit(q)"><span class='fa fa-pencil'></span></a>
            <a href='javascript:;' style="color: red;" (click)="delete(q)"><span class='fa fa-remove'></span></a>
         </th>
       </tr>
    </tbody>
    <!--判断没有试卷的情况的显示-->
  <tbody  *ngIf="questionaires==null||questionaires.length==0">
           <tr style="text-align: center;">
             <td colspan="6">暂无任务问卷信息</td>
           </tr>
  </tbody>
  <!--table的分页-->
<tr *ngIf="questionaires!=null">
  <td colspan="6">
    <div>
      <p style="float:left" *ngIf=" page>0">
        <i>显示{{(page-1)*pageSize+1 }} </i><i> {{page*pageSize
          < total ? page*pageSize :total }} </i>条记录,总共
        <i>{{total}}</i>
        &nbsp;&nbsp;&nbsp;每页显示
        <select  [ngModel]="pageSize"
                 (ngModelChange)="pageSize=$event;changePageSize()">
          <option *ngFor="let item of sizeList">{{item}}</option>
        </select>条记录
      </p>
      <!-- 分页功能 2017年10月29日20:09:00 end end  end end  end  -->
    </div>
  <div class="pagination" style="float: right">
    <ul>
      <li>
        <a style="cursor:pointer" (click)="topPage()">首页</a>
      </li>

      <li *ngIf="page >1"><a style="cursor:pointer" (click)="previousPage()">上一页</a></li>

      <li style="padding:0;border-width:0;">
        <a style="padding:0;border-width:0;cursor:pointer">
          <input #in class="custom-input" (keyup.enter)="changePage(in.value)" (blur)="changePage(in.value)" value={{page}} />
        </a>
      </li>
      <li *ngIf="page<totalPages">
        <a style="cursor:pointer" (click)="nextPage()">下一页</a>
      </li>
      <li>
        <a style="cursor:pointer" (click)="endPage()">尾页</a>
      </li>
    </ul>
</div>
  </td>
</tr>

</table>
</div>

2.控制器

//本页面只显示查询数据和显示数据的代码,如果知道更加详细的内容请联系我!
import {Component, Input, OnInit, Output,EventEmitter} from '@angular/core';
//引入service服务,负责与后台进行交互数据
import {InterceptorService} from '../../../../shared/interceptor.service';
//定义的试卷实体,以及试卷状态枚举(0,1,2)
import {MutiQuestionnaireModel,qState,qStatetoChinese} from '../../../../models/muti-questionnaire.model';
//路由类
import {Router} from '@angular/router';
//权限服务
import {AuthGuardService} from '../../../../shared/auth-guard.service'; 

@Component({
  selector: 'app-evaluation-table',
  templateUrl: './evaluation-table.component.html',
  styleUrls: ['./evaluation-table.component.css'],
})
export class EvaluationTableComponent implements OnInit {
  /**
   * 
   * @type {string}
   */
  url = 'exam-web/questionnaireManager/queryQuestionairByName';
  /**
  从父组件中获取数据:那种类型的问卷,问卷list,以及问卷的总数
  */
  //判断是调查问卷还是评教问卷,0代表评教问卷,1代表调查问卷
  @Input()  isQuestionnaire: number;
  @Input() questionaires: MutiQuestionnaireModel[]; //问卷list
  @Input()  total:number;
  tokenMsg: string = this.authGuardService.getTicket(); //获取权限的token数据
  // 分页内容
  pageSize = 5;  // 页面大小默认是10
  totalPages: number = this.total / this.pageSize;     // 总页数
  sizeList: Array<number> = [5, 10, 15, 20];  // 页大小的显示
  paging = false;          // 判断是否为真分页
  page:number=1;
  constructor(private  http: InterceptorService, private  router: Router,
           private authGuardService : AuthGuardService) {
  }

  ngOnInit() {}


  getData(url: string,type:number): void {
  let  paperList: MutiQuestionnaireModel[]=[];
    this.http.get(this.url).subscribe(
      res => {
        if (res.json().code == '0000') {
          this.questionaires=[];
          paperList = res.json().data;
          paperList.forEach(item=>{
            if(item.type===type){
               this.questionaires.push(item);
            }
          });
          this.total = this.questionaires.length;
          this.totalPages = Math.ceil(this.total / this.pageSize);
        } else {
          this.msgs = [{
            severity: 'error',
            summary: '警告',
            detail: '获取已有试卷信息失败,请联系管理员'
          }];
        }
      }
    );
  }

  /**
   * 分页显示数据-2017-09-30 20:47:09
   */
  showData() {
    if (typeof this.pageSize == 'string') {
      this.pageSize = Number(this.pageSize);
    }
    if (this.paging) {
      this.getData(this.url,this.isQuestionnaire);
    }
  }

  /**页号 */
  // 改变页号,更新表格数据
  changePage(url: string, page: number, name): void {
    if (page > 0 && page < this.totalPages) {
      this.page = page;
      this.totalPages = Math.ceil(this.total / this.pageSize);
      this.getData(url,this.isQuestionnaire);
    } else {
      this.page = 1;
      this.showData();
    }
  }

  // 改变页大小,更新表格显示
  changePageSize(): void {
    this.page = 1;
    // math.ceil(x)返回大于参数x的最小整数
    this.totalPages = Math.ceil(this.total / this.pageSize);
    this.showData();
  }

  // 上一页
  previousPage() {
    this.page--;
  }

  // 下一页
  nextPage() {
    this.page++;
  }

  // 首页
  topPage() {
    this.page = 1;
  }

  // 尾页
  endPage() {
    this.page = this.totalPages;
  }

父组件

模板页面

<div class="container">
      <div class="row" style="margin-top:0px" [@fadeIn]>
          <div class="tab" role="tabpanel">
            <!-- Nav tabs -->
            <ul class="nav nav-tabs" role="tablist">
              <img  class="pro-img" alt=""/>
              <li role="presentation"  class="{{tabEActive}}"><a href="#Section1"  aria-controls="home" role="tab" data-toggle="tab"><span><i class="fa fa-user-plus"></i></span>评教问卷</a></li>
              <li role="presentation"  class="{{tabPActive}}"><a href="#Section2" aria-controls="messages" role="tab"  data-toggle="tab"><span><i class="fa fa-file-text-o"></i></span> 调查问卷</a></li>
            </ul>

            <!-- Tab tables-->
            <div class="tab-content tabs">
              <div role="tabpanel" data-target="evaluation" class={{tabETableActive}} id="Section1">
                <!--(0教师评教问卷 1课程调查问卷)-->
                <app-evaluation-table  [isQuestionnaire]="0" [total]="totalEvlaution"  [questionaires]="evaluation"></app-evaluation-table>
              </div>
              <div role="tabpanel"  class="{{tabPTableActive}}"  id="Section2">
                <app-evaluation-table  [isQuestionnaire]="1" [total]="totalPlain" [questionaires]="plain"></app-evaluation-table>
              </div>
            </div>
        </div>
</div>
</div>

控制器

/**
 * @author:常银玲
 * @function  父组件向子组件通信
 * @date:2017-09-30 20:34:55
 */
import {Component, Input, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {InterceptorService} from '../../../shared/interceptor.service';
import {AuthGuardService} from '../../../shared/auth-guard.service';
import {MutiQuestionnaireModel} from '../../../models/muti-questionnaire.model';
//动画效果
import {fadeIn} from '../../../animations/fade-in';

@Component({
  selector: 'evaluation-questionnaire',
  templateUrl: './teaching-evaluation-questionnaire.html',
  styleUrls: ['./teaching-evaluation-questionnaire.css'],
  animations: [fadeIn] //动画效果
})

export class EvaluationQuestionComponent implements OnInit {
  /**
   * 常银玲定义的变量
   * @type {string}
   */
  url = 'exam-web/questionnaireManager/queryQuestionairByName';
  isQuestionnaire: number;
  private questionaires: MutiQuestionnaireModel[];
  tokenMsg: string = this.authGuardService.getTicket();

  evaluation: MutiQuestionnaireModel[]=[]; //评教问卷
  plain:MutiQuestionnaireModel[]=[]; //调查问卷
  // 分页内容
  totalEvlaution: number;  // 总条数
  totalPlain:number;//调查问卷总条
  constructor(private  http: InterceptorService, private  router: Router,
             private authGuardService : AuthGuardService) {
  }
  ngOnInit() {
     this.getData(this.url);
  }

  // 获取后台全部的问卷数据,刚开始没有对问卷分类
  getData(url: string): void {
    this.evaluation=[];
    this.plain=[];
    this.http.get(this.url).subscribe(
      res => {
        if (res.json().code == '0000') {
          this.questionaires=res.json().data;
 //调查问卷的type是1,评教问卷的type是0,根据type的不同赋值给不同的问卷;
          this.questionaires.forEach(item=>{
            if(item.type===0){
              this.evaluation.push(item);
            }else{
              this.plain.push(item);
            }
          });
          this.totalEvlaution = this.evaluation ? this.evaluation.length : 0;
          this.totalPlain =this.plain ? this.plain.length:0;
        } else {
          this.msgs = [{
            severity: 'error',
            summary: '警告',
            detail: '获取已有试卷信息失败,请联系管理员'
          }];
        }
      }
    );
  }
}

注意:
父组件和子组件创建好了之后,子组件类应该export状态,暴露在外边;在需要使用该子组件的父模块中import这个组件,组件与组件之间才可以进行通信!

结语

其实理解angular组件的时候我们可以把他当成是一个公共的可以重复调用的接口,通过传送参数的形式获取数据的最终在页面的显示,大大节省了代码量,尤其是面对题型这种公共性的东西,使用组件可以简化我们的代码,但是使用组件应该清楚组件与组件之间传值的方式,可以帮助我们工作!本实例只是提供了简单的数据显示,想了解更多的代码,可以联系小编~~~~!

猜你喜欢

转载自blog.csdn.net/changyinling520/article/details/78261504
今日推荐