一、angular中的dom操作原生和ViewChild两种方式以及css3动画
1.原生操作
import { Component } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent {
flag: boolean = true
ngOnInit() {
//在这个生命周期函数里面,组件和指令只是初始化完成,不是dom加载完毕
var ownBox: any = document.getElementById("box")
ownBox.style.color = "red"
//所以dom元素上添加ngIf指令,控制台会报错
var ownBox2: any = document.getElementById("box1")
ownBox2.style.color = "blue"
}
ngAfterViewInit(): void {
//在这个生命周期函数就可以,因为dom加载完毕,建议dom操作防止此处
var ownBox2: any = document.getElementById("box1")
ownBox2.style.color = "blue"
}
}
<p>footer works!</p>
<div id="box">
这是一个盒子
</div>
<div id="box1" *ngIf="flag">
这是第2个盒子
</div>
2.ViewChild操作
//核心模块引入ViewChild
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent {
//装饰器获取dom节点,此处相当于把box dom节点赋值给了Box
@ViewChild("box") Box: any;
constructor() { }
ngAfterViewInit(): void {
// nativeElement在this.Box打印出后显示的方法
console.log(this.Box.nativeElement);
// 这样也可以操作
this.Box.nativeElement.style.color = "blue"
this.Box.nativeElement.style.width = "100px"
this.Box.nativeElement.style.height = "100px"
this.Box.nativeElement.style.background = "orange"
console.log(this.Box.nativeElement.innerHTML);//viewchild方法
}
}
<p #box>viewchild方法</p>
3.父子组件中通过ViewChild调用子组件的方法
父组件header.component.ts:
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
//装饰器
@ViewChild("child") Child: any
ngAfterViewInit(): void {
this.Child.children()
}
handle() {
//调用子组件里面的方法
this.Child.children()
}
}
父组件header.component.html:
<p>我是header组件</p>
<app-footer #child></app-footer>
<button (click)="handle()">获取子组件里面的方法</button>
子组件footer.component.ts:
//核心模块引入ViewChild
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent {
//装饰器获取dom节点,此处相当于把box dom节点赋值给了Box
@ViewChild("box") Box: any;
constructor() {
}
ngAfterViewInit(): void {
// nativeElement在this.Box打印出后显示的方法
console.log(this.Box.nativeElement);
// 这样也可以操作
this.Box.nativeElement.style.color = "blue"
this.Box.nativeElement.style.width = "100px"
this.Box.nativeElement.style.height = "100px"
this.Box.nativeElement.style.background = "orange"
console.log(this.Box.nativeElement.innerHTML);//viewchild方法
}
children() {
console.log("我是子组件里的方法");
}
}
4.css3动画
transition.component.html:
<div class="contain">
内容区域
<button (click)="show()">弹出侧边栏</button>
</div>
<aside id="aside">
侧边栏区域
</aside>
transition.component.scss定义样式:
#aside {
width: 200px;
height: 100%;
right: 0;
top: 0;
background-color: aqua;
position: absolute;
transform: translate(100%, 0);
transition: all 2s;
}
然后在style.scss设置全局样式,解决导航条显现问题:
body {
width: 100%;
overflow-x: hidden;
}
transition.component.ts获取dom并操作:
import { Component } from '@angular/core';
@Component({
selector: 'app-transition',
templateUrl: './transition.component.html',
styleUrls: ['./transition.component.scss']
})
export class TransitionComponent {
ngAfterViewInit(): void {
}
show() {
var aside1: any = document.getElementById("aside")
aside1.style.transform = "translate(0,0)"
}
}
二、父子之间通讯以及组件之间通讯
1.父组件给子组件@input
①子组件可以获取父组件的数据
②子组件可以执行父组件的方法
father.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-father',
templateUrl: './father.component.html',
styleUrls: ['./father.component.scss']
})
export class FatherComponent {
// 1.定义数据
msg = "我是通讯信息"
child() {
alert("我是父组件的方法")
}
}
father.component.html:
<p>我是父组件</p>
<hr>
<!-- 2.msg传值 child传方法 this传整个组件 -->
<app-child [msg]="msg" [child]="child" [every]="this"></app-child>
child.component.ts:
// 3.引入Input
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
@Input() msg: any
@Input() child: any
@Input() every: any
constructor() {
}
getFather() {
this.child()
console.log(this.every.msg);
}
}
child.component.html:
<!-- 获取父组件信息 -->
<p>我是子组件--{{msg}}</p>
<button (click)="getFather()">执行父组件传过来的方法</button>
2.子组件给父组件传值@ViewChild
①父组件可以获取子组件的数据
②父组件可以获取子组件的方法
father.compoent.ts:
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-father',
templateUrl: './father.component.html',
styleUrls: ['./father.component.scss']
})
export class FatherComponent {
@ViewChild("child") child: any
getChild() {
this.child.child()
}
}
father.compoent.html:
<p>我是父组件--{{child.msg}}</p>
<button (click)="getChild()">获取子组件里面的方法</button>
<hr>
<app-child #child></app-child>
child.compoent.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
// 定义数据
msg = "我是子组件的msg"
constructor() {
}
child() {
alert("我是子组件的方法")
}
}
child.compoent.html:
<p>我是子组件</p>
效果图:
3.子组件通过@Output触发父组件的方法
child.component.ts:
// 1.引入Output,EventEmitter
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent {
//2.new一个实例
@Output() public outer = new EventEmitter()
constructor() {
}
sendFather() {
alert(1111)
this.outer.emit("我是子组件的数据")
}
}
child.component.html:
<p>我是子组件</p>
<button (click)="sendFather()">通过@Output触发父组件方法</button>
father.component.ts:
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-father',
templateUrl: './father.component.html',
styleUrls: ['./father.component.scss']
})
export class FatherComponent {
@ViewChild("child") child: any
getChild() {
this.child.child()
}
run(e: any) {
alert("我是父组件的方法")
console.log(e);//获取到的时emit过来的数据
}
}
father.component.html:
<p>我是父组件</p>
<button (click)="getChild()">获取子组件里面的方法</button>
<hr>
<!-- 注意outer要和@Output() public outer = new EventEmitter()里面的outer一致 -->
<app-child #child (outer)="run($event)"></app-child>
4.非父子组件传值:
1.组件之间传值可以使用localstorage
2.共享方法可以使用service(可参考上篇使用)
三、生命周期函数
这里只讲一下使用,详细钩子请参考官网:Angular - 生命周期钩子
import { Component, ViewChild } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor() {
console.log("0-constructor---除了使用简单的值对局部变量进行初始化之外,什么都不用做");
}
ngOnChanges() {
console.log("1-ngOnChanges---当被绑定的输入属性的值发生变化时调用,父子传值时会被触发");
}
ngOnInit() {
console.log("2-ngOnInit---请求数据一般放在这里");
}
ngDoCheck() {
console.log("3-ngDoCheck---检测,并在angular发生无法或者不愿自己检测的变化时作出反应");
}
ngAfterContentInit() {
console.log("4-ngAfterContentInit---当把内容投影到组件之后调用");
}
ngAfterContentChecked() {
console.log("5-ngAfterContentChecked---每次完成被投影组件内容的变更检测之后调用");
}
ngAfterViewInit() {
console.log("6-ngAfterViewInit---初始化完组件视图及其子视图之后调用,dom操作放在这个里面");
}
ngAfterViewChecked() {
console.log("7-ngAfterViewChecked---每次完成组件视图和子视图的变更检测之后调用");
}
ngOnDestroy() {
console.log("8-ngOnDestroy---销毁");
}
}
四、RxJS(类似于vue中的promise)
RxJS是 ReactiveX编程理念的JavaScript版本。ReactiveX来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括HTTP请求,DOM事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。
RxJS是一种针对异步数据流编程工具,或者叫响应式扩展编程;可不管如何解释RxlS其目标就是异步编程,Angular引入 RxJS为了就是让异步可控、更简单。RxlS里面提供了很多模块。这里我们主要使用RxJS里面最常用的Observable和fromEvent。
目前常见的异步编程的几种方法:
1.回调函数
comoon.service.ts:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ComoonService {
constructor() {
}
out() {
return "service"
}
//解决方式,传入回调函数
data(cb: any) {
setTimeout(() => {
var data = "张三"
// return data
cb(data)
}, 1000)
}
}
header.component.ts:
import { Component } from '@angular/core';
import { ComoonService } from "../../services/comoon.service"
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor(public res: ComoonService) {
}
ngOnInit() {
// let str = this.res.data()
//undefined,获取不到service里的异步
// console.log(str);
this.res.data((data: any) => {
console.log(data);//张三
})
}
}
2.事件监听/发布订阅
3.promise
comoon.service.ts:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ComoonService {
constructor() {
}
PromiseData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
var username = "张三"
resolve(username)
}, 1000)
})
}
}
header.component.ts:
import { Component } from '@angular/core';
import { ComoonService } from "../../services/comoon.service"
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor(public res: ComoonService) {
}
ngOnInit() {
let getData = this.res.PromiseData()
getData.then((data) => {
console.log(data);//张三
})
}
}
4.Rxjs
comoon.service.ts:
import { Injectable } from '@angular/core';
//1.引入Observable
import { Observable } from "rxjs"
@Injectable({
providedIn: 'root'
})
export class ComoonService {
constructor() {
}
// 2.使用,其中observe为参数可以自定义
RxjsData() {
return new Observable((observe) => {
setTimeout(() => {
var username = "张三"
observe.next(username)
}, 1000)
})
}
}
header.component.ts:
import { Component } from '@angular/core';
import { ComoonService } from "../../services/comoon.service"
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor(public res: ComoonService) {
}
ngOnInit() {
var RxjsData = this.res.RxjsData()
// 通过subscribe返回数据
RxjsData.subscribe((data) => {
console.log(data);
})
}
}
从上面例子我们感觉promise和 RxJS 的用法基本相似。其实Rxjs相比promise要强大很多。比如Rxjs中可以中途撤回、Rxjs可以发射多个值、RxJS提供了多种工具函数等等。
5. Rxjs unsubscribe取消订阅
promise的创建之后,动作是无法撤回的。Observable不一样,动作可以通过unsbscribe()方法中途撤回,而且Observable在内部做了智能的处理。
header.component.ts:
import { Component } from '@angular/core';
import { ComoonService } from "../../services/comoon.service"
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor(public res: ComoonService) {
}
ngOnInit() {
var RxjsData = this.res.RxjsData()
// 通过subscribe返回数据
var result = RxjsData.subscribe((data) => {
console.log(data);
})
// 取消订阅,注意定时器时间要小于service定时器的时间
setTimeout(() => {
result.unsubscribe()
}, 1000)
}
}
6. Rxjs订阅后多次执行
如果我们想让异步里面的方法多次执行,这一点 Promise是做不到的,对于Promise来说,最终结果要么resole(兑现)、要么reject(拒绝),而且都只能触发一次。如果在同一个Promise 对象上多次调用resolve方法,则会抛异常。而 Observable不一样,它可以不断地触发下一个值,就像 next()这个方法的名字所暗示的那样。
comoon.service.ts:
import { Injectable } from '@angular/core';
//1.引入Observable
import { Observable } from "rxjs"
@Injectable({
providedIn: 'root'
})
export class ComoonService {
constructor() {
}
RxjsData() {
let num = 0
return new Observable((observe) => {
setInterval(() => {
num++
var username = "张三" + num
observe.next(username)
}, 1000)
})
}
}
header.component.ts:
import { Component } from '@angular/core';
import { ComoonService } from "../../services/comoon.service"
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
constructor(public res: ComoonService) {
}
ngOnInit() {
var RxjsData = this.res.RxjsData()
// 通过subscribe返回数据
var result = RxjsData.subscribe((data) => {
console.log(data);
})
}
}
以上效果promise只执行一次。