视频回放 【34.2】工程的进一步改造—— 善用 @ViewChild

应用场景

这是一个带有数据交互的网页,如下图。

上半部分实现添加商品,下半部分是商品列表展示。 当添加一个商品后, 商品列表会自动展示出来,无需刷新页面。

image.png

实现思路:

在直播课程中,我们讲述了它的实现方法, 当时是通过 @Output() 装饰符实现的。 @Output() 理解起来还是有些“绕”。
这次,我们换一种实现方法, 通过 @ViewChild() 装饰符来实现。

关于 @ViewChild()

@Input@Output() 一样, @ViewChild 也是一个很重要的 Decorator (装饰符), 它的应用场景是:
当Parent component 对 child component 进行存取操作时,可用到 @ViewChild

关键技术点

在 Parent Component ,要用到 AfterViewInit

按照 Angular 机制, 我们可以在 parent component 中,通过 @ViewChild() decorator (装饰符)来声明一个属于 child component 的成员属性变量, 然后,就可以对这个 child component 进行存在操作,比如: 调用 child component 的属性变量,调用 child component 的方法。

@ViewChild() 里面的参数,要传入所引入的 child component。

需要注意的是: 要想通过 @ViewChild() 存取 child component 的 pubic field (默认的是 pubic 属性), 必须在 ngAfterViewInit() lifecycle hook 中才能抓到它,不可以在 ngOnInit() 中。

说了这么多, 还是上代码吧!

代码实现

实现思路:

把整个页面放在一个component中 (home.component), 下方的商品列表放在另外一个独立的 component 中(product-list.component)。 首页(home)是一个筐,里面有多个 component 组成。

// home.component.html
<div class="container">
  <h3 class="text-center"> 创建商品 </h3>
  <form >
  <div class="form-group">
    <label for="username"> 商品名称: </label>
    <input type="text" class="form-control" placeholder="请输入商品名称" [(ngModel)]= "title"  name = "key_title">
  </div>

  <div class="form-group">
    <label for="text">商品价格: </label>
    <input type="text" class="form-control" placeholder="请输入商品价格" [(ngModel)]= 'price'  name = "key_price">
  </div>

  <div class="form-group">
    <input type = "button" class = "btn btn-primary" value ="添加商品" (click)="createProduct()"> 
  </div>
</form>
</div>

<app-product-list>  </app-product-list>> 

注意上面的代码:

<app-product-list> </app-product-list>>

// home.component.ts
import { Component, OnInit, ViewChild ,AfterViewInit } from '@angular/core';

import {ProductListComponent}   from '../product-list/product-list.component'

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, AfterViewInit {

  @ViewChild (ProductListComponent)  private  productListComponent : ProductListComponent; 

   title: string;
   price:  string; 

  ngAfterViewInit(): void {   }

  constructor() { }

  ngOnInit() {
  }
   
  createProduct(){
    let myProduct : any = {
     title: this.title,
     price: this.price,
    };
    this.productListComponent.addProduct( myProduct )
  }
}

注意以上关键代码:

@ViewChild (ProductListComponent) private productListComponent : ProductListComponent;

再来看商品列表组件的实现

// product-list.component.html
<div class="container">
  <h3 class="text-center">商品列表</h3>
  <table class="table table-dark table-hover table-striped">
    <thead class="thead-light">
      <tr>
        <th>商品名称</th>
        <th>商品价格</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let p of products">
        <td>{{p.title}}</td>
        <td>{{p.price}}</td>
      </tr>
    </tbody>
  </table>
</div>

// product-list.component.ts 
import { Component, OnInit } from '@angular/core';
import { Product } from "../product";

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {

  products: Product[];
  myProduct: any; 
  constructor() {
    this.products = new Array <Product>();    // 必须的,否则报错, 创建对象的实例

   }
  ngOnInit() {

    this.products = [
      { title: "第 1 件商品", price: 11 },
      { title: "第 2 件商品", price: 22 },
      { title: "第 3 件商品", price: 33 },
      { title: "第 4 件商品", price: 44 },
      { title: "第 5 件商品", price: 55 },
    ];
  
  }

  addProduct( obj: any ){
      this.myProduct = {
      title :  obj.title,
      price:   obj.price
    }
    this.products.push( this.myProduct );
    console.log("收到了来自 child 组件的数据",this.products);
   }
}

product.ts

export class Product {
    title : string;
    price : number; 
}

小结

当一个页面由多个组件构成,且组件之间有数据交互发生时, 可以通过 @ViewChild 装饰符来实现。 可以这样说, 只要是 UI 相关的开发,都要解决 组件之间的数据交互问题, 不同框架的命名方式都很接近。都带有 child 字样,比如 iOS 中的 addChildViewController 等等。 一通百通!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345