[TOC]
>[success] # 在组件类中引用模版(类似vue 的 ref)
>[success] ## 获取普通dom 元素
![](https://img.kancloud.cn/7b/0a/7b0a83c457fa51a828f060ae2fa71516_1012x536.png)
这个好像 **vue2.x** 中的根据 **ref 调用子组件方法** ,我们首先在想要获取dom的标签身上添加 `#名称` ,例子:
**html代码**
~~~
<div class="container">
<div class="image-slider" #imageSlider> // 名称
<img
*ngFor="let slider of sliders"
[src]="slider.imgUrl"
[alt]="slider.caption"
/>
</div>
<div class="nav-section">
<span
*ngFor="let _ of sliders; let idx = index"
class="slide-button"
></span>
</div>
</div>
~~~
**ts代码**
~~~
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
export interface ImageSlider {
imgUrl: string;
link: string;
caption: string;
}
@Component({
selector: 'app-image-slider',
templateUrl: './image-slider.component.html',
styleUrls: ['./image-slider.component.css']
})
export class ImageSliderComponent implements OnInit {
@Input() sliders: ImageSlider[] = [];
// 获取dom元素
@ViewChild('imageSlider', { static: true }) imgSlider!: ElementRef;
constructor() {}
ngOnInit() {
// 对 dom 进行操作
this.imgSlider.nativeElement.innerHTML = `<span>Hello</span>`;
}
}
~~~
然后在获取 **dom** 的 **ts** 代码中,像上面这样写,用 **@ViewChild 装饰器选择** 我们定义好的 **#名称** 的标签,这里需要 **注意:如果我们获取的这个 dom 元素在 ng-if 或者 ng-for 包含下,static 就需要设置为 false,如果没有被 ng-if 或者 ng-for 包裹,就设置为 true,默认 false** ,然后起一个变量 **imgSlider** 来储存这个接收 **dom元素** 的 **ref** ,然后 **ElementRef** 是 **dom元素** 的 **类型** 。
>[success] ## 获取angular组件元素
![](https://img.kancloud.cn/93/63/9363726a35421508fd19991941b8fcbe_1064x508.png)
>[success] ### 普通方式获取
代码如下:
**html代码**
~~~
<!-- 引入组件 -->
<app-scrollable-tab
[menus]="topMenus"
(tabSelected)="handleTabSeleted($event)"
[backgroundColor]="scrollableTabBgColor"
titleColor="#fff"
titleActiveColor="yellow"
indicatorColor="yellow"
*ngIf="scrollableTabBgColor === 'red'"
>
</app-scrollable-tab>
<app-image-slider [sliders]="imageSliders" #imageSlider></app-image-slider>
~~~
**ts代码**
~~~
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { TopMenu, ImageSlider, ImageSliderComponent } from './components'; // 引入子组件中定义得接口
@Component({
selector: 'app-root', // 组件名称
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
// 以下是类似vue的变量跟方法
export class AppComponent implements AfterViewInit {
@ViewChild('imageSlider') imageSlider!: ImageSliderComponent;
// selectedIndex = -1; // 高亮选中的颜色下标
topMenus: TopMenu[] = [
// 菜单列表
{
title: '热门',
link: ''
},
{
title: '男装',
link: ''
},
{
title: '百货',
link: ''
},
{
title: '运动',
link: ''
},
{
title: '手机',
link: ''
},
{
title: '家纺',
link: ''
},
{
title: '食品',
link: ''
},
{
title: '电器',
link: ''
},
{
title: '鞋包',
link: ''
},
{
title: '汽车',
link: ''
},
{
title: '水果',
link: ''
},
{
title: '电脑',
link: ''
},
{
title: '内衣',
link: ''
},
{
title: '家装',
link: ''
},
{
title: '母婴',
link: ''
},
{
title: '美妆',
link: ''
},
{
title: '家具',
link: ''
}
];
scrollableTabBgColor = 'red';
imageSliders: ImageSlider[] = [
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.kB-Ovasi0GW67-rmwnAcwAHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.nfC2tVNM9TgwQ5QuqECd6wHaFj&w=288&h=216&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.rHuc8SKa0wLVwCqqA27uIwHaEt&w=313&h=199&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.i0-ND27ia6sO-nZuY9f7qAHaEK&w=333&h=187&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
}
];
handleTabSeleted(tabMenu: TopMenu) {
const colors = ['red', 'blue', 'black'];
const idx = Math.floor(Math.random() * 3);
this.scrollableTabBgColor = colors[idx];
}
ngAfterViewInit(): void {
console.log(this.imageSlider, '获取angular的组件');
}
}
~~~
>[success] ### 快速方式获取
区别:
1. **html 代码** 中的 **组件标签上** 不用声明 **#名称**
2. **ts 代码中** 的 **@ViewChild** 装饰器不用传入 **#名称** ,**直接传入组件** ,如下图:
![](https://img.kancloud.cn/7b/6d/7b6da6a7a30f85e48f0147f4000af8ea_1047x670.png)
具体代码如下:
**html代码**
~~~
<!-- 引入组件 -->
<app-scrollable-tab
[menus]="topMenus"
(tabSelected)="handleTabSeleted($event)"
[backgroundColor]="scrollableTabBgColor"
titleColor="#fff"
titleActiveColor="yellow"
indicatorColor="yellow"
*ngIf="scrollableTabBgColor === 'red'"
>
</app-scrollable-tab>
<app-image-slider [sliders]="imageSliders"></app-image-slider>
~~~
**ts代码**
~~~
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { TopMenu, ImageSlider, ImageSliderComponent } from './components'; // 引入子组件中定义得接口
@Component({
selector: 'app-root', // 组件名称
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
// 以下是类似vue的变量跟方法
export class AppComponent implements AfterViewInit {
@ViewChild(ImageSliderComponent) imageSlider!: ImageSliderComponent;
// selectedIndex = -1; // 高亮选中的颜色下标
topMenus: TopMenu[] = [
// 菜单列表
{
title: '热门',
link: ''
},
{
title: '男装',
link: ''
},
{
title: '百货',
link: ''
},
{
title: '运动',
link: ''
},
{
title: '手机',
link: ''
},
{
title: '家纺',
link: ''
},
{
title: '食品',
link: ''
},
{
title: '电器',
link: ''
},
{
title: '鞋包',
link: ''
},
{
title: '汽车',
link: ''
},
{
title: '水果',
link: ''
},
{
title: '电脑',
link: ''
},
{
title: '内衣',
link: ''
},
{
title: '家装',
link: ''
},
{
title: '母婴',
link: ''
},
{
title: '美妆',
link: ''
},
{
title: '家具',
link: ''
}
];
scrollableTabBgColor = 'red';
imageSliders: ImageSlider[] = [
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.kB-Ovasi0GW67-rmwnAcwAHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.nfC2tVNM9TgwQ5QuqECd6wHaFj&w=288&h=216&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.rHuc8SKa0wLVwCqqA27uIwHaEt&w=313&h=199&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
},
{
imgUrl:
'https://s.cn.bing.net/th?id=OIP-C.i0-ND27ia6sO-nZuY9f7qAHaEK&w=333&h=187&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
link: '',
caption: ''
}
];
handleTabSeleted(tabMenu: TopMenu) {
const colors = ['red', 'blue', 'black'];
const idx = Math.floor(Math.random() * 3);
this.scrollableTabBgColor = colors[idx];
}
ngAfterViewInit(): void {
console.log(this.imageSlider, '获取angular的组件');
}
}
~~~
>[success] ## 获取 ng-for 循环添加的 ref 元素
![](https://img.kancloud.cn/5d/43/5d43618c8c193099dc6cd96a0648026a_958x544.png)
获取 **ng-for 循环** 出来的 **dom 元素** ,需要使用 **@ViewChildren 装饰器** ,定义类型时使用 **QueryList<ElementRef\>** 才可以,然后下面还使用了 **angular** 提供的注入中的 **Renderer2** 方法,来 **修改dom 元素样式** 具体写法如下:
**html代码**
~~~
<div class="container">
<div class="image-slider" #imageSlider>
<img
#img // 定义dom选择的名称
*ngFor="let slider of sliders"
[src]="slider.imgUrl"
[alt]="slider.caption"
/>
</div>
<div class="nav-section">
<span
*ngFor="let _ of sliders; let idx = index"
class="slide-button"
></span>
</div>
</div>
~~~
**ts代码**
~~~
import {
Component,
ElementRef,
Input,
OnInit,
QueryList,
ViewChild,
ViewChildren,
AfterViewInit,
Renderer2
} from '@angular/core';
export interface ImageSlider {
imgUrl: string;
link: string;
caption: string;
}
@Component({
selector: 'app-image-slider',
templateUrl: './image-slider.component.html',
styleUrls: ['./image-slider.component.css']
})
export class ImageSliderComponent implements OnInit, AfterViewInit {
@Input() sliders: ImageSlider[] = [];
// 获取dom元素
@ViewChild('imageSlider', { static: true }) imgSlider!: ElementRef;
// 获取循环出来的dom元素
@ViewChildren('img') imgs!: QueryList<ElementRef>;
// eslint-disable-next-line @typescript-eslint/no-empty-function
constructor(private rd2: Renderer2) {}
// 组件初始化
ngOnInit() {
// 对 dom 进行操作
// this.imgSlider.nativeElement.innerHTML = `<span>Hello</span>`;
}
// 视图完全渲染完成(在这里才能打印出来所有dom元素,在ngOnInit里打印不出来 this.imgs ,因为还没有渲染结束,如果想对dom操作还是在 ngAfterViewInit中操作比较稳妥)
ngAfterViewInit(): void {
// 原生js方式修改样式
// this.imgs.forEach((item) => {
// item.nativeElement.style.height = '100px';
// });
// angular推荐方式修改样式
this.imgs.forEach((item) => {
this.rd2.setStyle(item.nativeElement, 'height', '100px');
});
}
}
~~~
**dom元素** 的打印结果:
![](https://img.kancloud.cn/92/37/9237c159d10a0c6d70fd751ca5d84b49_618x446.png)
>[success] ## 总结
![](https://img.kancloud.cn/72/01/720155ce39bb9ddb3cd2b7cb4cffe1f3_990x498.png)
- Angular8开发拼多多WebApp
- 框架对比
- 环境搭建与项目创建
- 开发工具配置
- 初始组件
- ngFor指令
- ngIf指令
- 样式绑定的几种方式
- 组件生命周期
- 在组件类中引用模版(类似vue 的 ref)
- 双向绑定
- 什么是模块
- 【以下目录未完成】什么是注解(装饰器)
- 指令的概念
- 组件的事件绑定和样式绑定
- 组件嵌套和投影组件
- 路由概念
- 路由实战
- 路由URL和参数
- 管道的概念
- 依赖注入
- 脏值检测
- HTTP 概览
- Postman 和 Rest Client 调试 HTTP
- Rest API
- HttpClient 修改
- Http 拦截器 HttpInterceptor
- 其他
- Angular终极课程
- RxJS快速入门