一、前言

Angular是一个类似于后端开发模式的前端开发框架,学习起来非常简单,当然需要一定的前端基础,本篇接着第一节继续介绍Angular基础
学习过程中所写的Demo_GitHub——学习Angular——浅度学习Demo
官网:https://angular.cn/(官网是最好的老师哦,追求技术的大神可以继续深入啦)

二、声明周期函数

当 Angular 实例化组件类并渲染组件视图及其子视图时,组件实例的生命周期就开始了。生命周期一直伴随着变更检测,Angular 会检查数据绑定属性何时发生变化,并按需更新视图和组件实例。当 Angular 销毁组件实例并从 DOM 中移除它渲染的模板时,生命周期就结束了。当 Angular 在执行过程中创建、更新和销毁实例时,指令就有了类似的生命周期。
说得简单点,就是在创建-销毁组件的过程中,有一系列的方法会被默认执行
这部分知识点可以参考官网

根据习惯还是先看案例,再详细讲解:
子组件:
HTML

<h1>lifecycle-method works!</h1>
<h2 #count ></h2>
<button (click)="countOperation()">累加</button>
<hr>
<br>
<hr>
<br>

TS文件

import {AfterContentChecked,AfterContentInit,AfterViewChecked,AfterViewInit,Component,DoCheck,OnChanges,OnDestroy,OnInit,ViewChild,Input
} from '@angular/core';// tslint:disable-next-line:no-conflicting-lifecycle
@Component({selector: 'app-lifecycle-method',templateUrl: './lifecycle-method.component.html',styleUrls: ['./lifecycle-method.component.scss']
})
export class LifecycleMethodComponent implements OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit,AfterViewChecked, OnDestroy{@Input() childData: any;num = 0;@ViewChild('count') count: any;// 构造方法constructor() {console.log('000 构造方法被执行---除了对局部变量的初始化,不应该进行其他操作(重点)');}ngOnChanges(): void{// 此组件作为子组件,被父组件传值的时候才会被调用,并且每次父组件传值过来时都会被调用,这里就不写例子了,很好理解console.log('001 ngOnChanges()被调用---当被绑定输入属性的值发生变化时被调用,一般为父子组件传值');}ngOnInit(): void {console.log('002 ngOnInit()被调用---请求数据一般被放到这里(重点)');}ngDoCheck(): void{console.log('003 ngDoCheck()被调用---检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应');}ngAfterContentInit(): void{console.log('004 ngAfterContentInit()被调用---当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。');}ngAfterContentChecked(): void{console.log('005 ngAfterContentChecked()被调用---每当 Angular 检查完被投影到组件或指令中的内容之后调用。');}ngAfterViewInit(): void{console.log('006 ngAfterViewInit()被调用---当 Angular 初始化完组件视图及其子视图或包含该指令的视图之后调用,一般进行dom操作(重点)');}ngAfterViewChecked(): void{console.log('007 ngAfterViewChecked()被调用---每当 Angular 做完组件视图和子视图或包含该指令的视图的变更检测之后调用。');}ngOnDestroy(): void{console.log('008 ngOnDestroy()被调用---每当 Angular 每次销毁指令/组件之前调用并清扫,当组件进行路由时会触发此声明周期函数(重点)');}countOperation(): void{this.num ++;this.childData ++;this.count.nativeElement.innerHTML = this.num;}
}

父组件:
HTML

<app-lifecycle-method *ngIf="exist" [childData]="title"></app-lifecycle-method><button (click)="changeTitle()">触发ngOnChanges()</button>
<button (click)="destroy()">触发ngOnDestroy()</button>

TS文件

// 引入核心模块中的Component
import { Component } from '@angular/core';@Component({selector: 'app-root', // 组件的名字templateUrl: './app.component.html', // HtmlstyleUrls: ['./app.component.scss'] // css
})
export class AppComponent {title = 'demo1'; // 定义属性exist: any = true;constructor(){  // 构造函数}changeTitle(): void{this.title = this.title + '1';}destroy(): void{this.exist = !this.exist;}
}

先提一下,不知道我又没有在第一节讲,不过我们使用哪个组件,一个很关键的操作就是将它加入到index.html页面中,因为Angular是单页面应用,也就是说它只会显示index.html,所以只有加入到index.html的视图才会被显示

说到生命周期函数,Angular一共有8个加上构造方法,上面的Demo也算是非常详细的展示了他们的执行顺序以及触发条件,这里讲详细讲解一下其中重点的生命周期函数

  1. constructor(): 构造方法,一般在其中引入一些服务或者进行局部数据的初始化
  2. ngOnInit(): 一般请求数据是放到这里边的,然后存储到类数据中,对页面进行渲染
  3. ngAfterViewInit():这个是在页面和组件加载完成后才会触发的生命周期函数,一般是进行一些dom操作的
  4. ngOnDestroy():销毁方法,一般是在组件被注销或者路由到其他组件时触发,可以进行一些保存数据的操作,防止数据丢失

基本上,上面四个函数就够用了,其他的可以有个印象就足够了,项目中真的用到了也可以随时查看官网的文档,很方便的。

三、Rxjs 异步调用

本人使用的比较浅显,感觉这个rxjs第三方包主要对异步调用提供了更加完善的支持。rxjs本来是第三方包,但是在Angular7之后就被集成到了Angular中了,基于这个情况,直接使用就可以了

直接上Demo,根据Demo进行解释这个功能点的含义
Service服务

import { Injectable } from '@angular/core';
import {Observable} from 'rxjs';@Injectable({providedIn: 'root'
})
export class DataStorageService {constructor() { }set(key: string, value: any): void{localStorage.setItem(key, JSON.stringify(value));}get(key: string): any{return JSON.parse(localStorage.getItem(key));}remove(key: string): void{localStorage.removeItem(key);}
// 同步方法getData(): any{const data = '这是一个同步方法';return data;}
// 异步方法getAsynData(): any{setTimeout( () => {const data = '这是一个异步方法';return data;}, 1000);}
// 函数回调解决异步getFunData(fun): void{setTimeout( () => {const data = '这是一个函数回调解决异步方法';fun(data);}, 1000);}
// 通过ES6 Promise 解决异步调用getPromiseData(): any{return new Promise((resolve, reject) => {setTimeout( () => {const data = '这是一个Promise解决异步的方法';resolve(data);}, 1000);});}
// 通过 rxjs Observable 解决异步的方法getRxjsData(): any{// tslint:disable-next-line:no-shadowed-variablereturn new Observable((observable) => {setTimeout( () => {const data = '这是一个rxjs解决异步的方法';observable.next(data);// observable.error(''); 返回一个错误的信息}, 1000);});}// 多次调用getRxjsInterval(): any{// tslint:disable-next-line:no-shadowed-variablereturn new Observable((observable) => {setInterval( () => {const data = '这是一个rxjs解决异步的方法-多次调用';observable.next(data);// observable.error(''); 返回一个错误的信息}, 1000);});}getRxjsNum(): any{return new Observable((observable) => {let num = 0;setInterval(() => {num ++;observable.next(num);}, 1000);});}
}

组件

import { Component, OnInit } from '@angular/core';
import {DataStorageService} from '../../services/data-storage.service';
import { filter, map } from 'rxjs/operators';@Component({selector: 'app-rxjs-data',templateUrl: './rxjs-data.component.html',styleUrls: ['./rxjs-data.component.scss']
})
export class RxjsDataComponent implements OnInit {constructor(public storage: DataStorageService) { }ngOnInit(): void {let data = this.storage.getData();console.log(data);data = this.storage.getAsynData();console.log(data);this.storage.getFunData((da) => {console.log(da);});const promise = this.storage.getPromiseData();promise.then((da) => {console.log(da);});const observable = this.storage.getRxjsData();observable.subscribe((da) => {console.log(da);});// 从上述看,rxjs并没有比Promise强到哪里,为什么不使用ES6的Promise,而选择第三方包的rxjs呢?// 很简单,因为rxjs支持订阅中断、重复订阅等功能const observableInterval: any = this.storage.getRxjsInterval();const inter: any = observableInterval.subscribe((da) => {console.log(da);});// 中断订阅setTimeout(() => {inter.unsubscribe();},3000);// pipe 工具const num = this.storage.getRxjsNum();num.pipe(filter((val) => {// @ts-ignorereturn 0 === val % 2 ;}),map((val) => {// @ts-ignorereturn val * val;})).subscribe((da) => {console.log(da);});}
}

要使用rxjs是要inport它的包的,这个是肯定需要的,不要忘了。
Demo主要解释了异步调用所面临的问题,而它的解决方法也比较多,下面列出来:

  1. 回调方法
  2. ES6的Promise
  3. Rxjs

可以看到回调方法,在我理解中和java JDK8的lambda语法很像,就是传递过一个匿名函数代码块

Promise是ES6支持的处理异步的方法,可以处理成功和失败两种返回。

Rxjs的Observable,看起来和Promise差不多,但是功能却要完善很多,可以额外支持订阅中断、多次订阅等,而且提供了工具包,类似于filter、map,插一句外话,这个和jdk8中的stream也是非常像的,都是对数据的预处理。

四、Http请求

Angular中Http请求还是比较简单的,都是利用封装好的服务,当然也可以使用第三方的组件去进行http请求,这里都是简单介绍,其实我认为官网这块写的已经很不错了

import { Injectable } from '@angular/core';
import {HttpClient, HttpHandler, HttpHeaders} from '@angular/common/http';
import axios from 'axios';
import {Observable} from 'rxjs';@Injectable({providedIn: 'root'
})
export class HttpsentService {private url: any = 'http://localhost:8099/';constructor(private http: HttpClient) {}get(param: any): any{return this.http.get(`${this.url}get`);}post(param: any): any{// 设置请求头let handler = {headers: new HttpHeaders({'Content-Type':  'application/json'})};return this.http.post(`${this.url}post`,param, handler);}jsonp(): any{return this.http.jsonp(`${this.url}jsonp`,'callback');}axiosGet(): any{return new Observable((observable) => {axios.get(`${this.url}get`).then((data) =>{observable.next(data);})})}}

这块就不详细写了,很零碎,主要是要使用http请求,一定要在app.module.ts中引入

import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

这个,然后在import中引入。之后哪里需要使用http请求就在哪里引入就好了
,上边demo中 分别是get、post、jsonp已经axios的get请求,前三个官网都有介绍,我主要把后端代码贴过来吧,也很简单的web请求(java)

package com.consul.provider.service.impl;import com.alibaba.fastjson.JSON;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;/*** @program: springCloud* @description: 应对与Angular的请求测试类* @create: 2020-11-23 17:51**/
//@CrossOrigin
@RestController
public class TestController {@CrossOrigin@GetMapping("get")public Object get(String param){return JSON.toJSONString("Get 请求,传过来的参数是 "+param);}/*** @RequestBody : 可以直接整个接受 json对象* @RequestParam: JSON参数*/@CrossOrigin@PostMapping("post")public Object post(@RequestBody Object object){System.out.println(JSON.toJSONString(object));return JSON.toJSONString("Post 请求,传过来的参数是 "+JSON.toJSONString(object));}@GetMapping("jsonp")public Object jsonp(HttpServletRequest request){try {String callback=request.getParameter("callback");if("".equals(callback)){return ResponseEntity.status(HttpStatus.OK).body("Jsonp 请求");}else{//包裹callback函数,给js解析。return ResponseEntity.ok(callback+"("+JSON.toJSONString("Jsonp 请求")+")");}} catch (Exception e) {e.printStackTrace();}return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);}
}

后端这里主要是接受请求,判断一下前端是否发送成功,所以也比较简单,这里其实关于jsonp这里我研究了一天,主要是这个地方以前听说过,但没有实际接触过,了解后还是有点一知半解,不敢说懂了,所以想深入了解的朋友还是自行百度吧

对了,要想在使用第三方包axios的朋友,需要引入依赖

cnpm install axios --save

这样就可以在需要的地方,引入使用了
这节很简单,没啥说的,不会的话留言吧

五、路由

寻求进阶请看官网路由文档
在单页面应用中,你可以通过显示或隐藏特定组件的显示部分来改变用户能看到的内容,而不用去服务器获取新页面。当用户执行应用任务时,他们要在你预定义的不同视图之间移动。要想在应用的单个页面中实现这种导航,你可以使用 Angular 的Router(路由器)。
为了处理从一个视图到下一个视图之间的导航,你可以使用 Angular 的路由器。路由器会把浏览器 URL 解释成改变视图的操作指南,以完成导航。

着重提一下Angular 中的路由顺序
路由的顺序很重要,因为 Router 在匹配路由时使用“先到先得”策略,所以应该在不那么具体的路由前面放置更具体的路由。首先列出静态路径的路由,然后是一个与默认路由匹配的空路径路由。通配符路由是最后一个,因为它匹配每一个 URL,只有当其它路由都没有匹配时,Router 才会选择它。

其他的基础知识点以Demo的形式看一下吧

路由跳转
app-routing.module.ts文件

const routes: Routes = [{path: 'mvvm', component: FormMVVMComponent},{path: 'logic', component: LogicComponent},{path: 'news', component: NewsComponent},{path: 'newsDetail', component: NewDetailComponent},{path: 'newsDetailDynamic/:sid', component: NewsDetailDynamicComponent},{path: 'fc_router', component: FCRouterComponent,children: [{path: 'f_router', component: FRouterComponent,children: [{path: 'f_one', component: FOneDetailComponent},{path: 'f_two', component: FTwoDetailComponent}]},{path: 'c_router', component: CRouterComponent,children: [{path: 'c_one', component: COneDetailComponent},{path: 'c_two', component: CTwoDetailComponent}]}]},{path: '**', redirectTo: '/fc_router'}
];

上面是路由的配置文件,其中不但包括了路由跳转的基本路由配置,还包括了父子嵌套路由的配置,就是这段

{path: 'fc_router', component: FCRouterComponent,children: [{path: 'f_router', component: FRouterComponent,children: [{path: 'f_one', component: FOneDetailComponent},{path: 'f_two', component: FTwoDetailComponent}]},{path: 'c_router', component: CRouterComponent,children: [{path: 'c_one', component: COneDetailComponent},{path: 'c_two', component: CTwoDetailComponent}]}]}

父路由组件
Html

<h3>新闻列表</h3>
<h4>Url请求</h4>
<ul><li *ngFor="let item of list, let key=index"><!--[routerLink]="'newsDetail'" ==> http://127.0.0.1:4200/news/newsDetail[routerLink]="'/newsDetail'" ==> http://127.0.0.1:4200/newsDetail--><a *ngIf="key % 2 ==0" [routerLink]="['/newsDetail']" [queryParams]="{sid:key}">{{item}}</a><a *ngIf="key % 2 !=0" [routerLink]="['/newsDetailDynamic/',key]">{{item}}</a></li>
</ul><hr>
<br>
<h4>TS跳转</h4>
<ul><li *ngFor="let item of list, let key=index"><a *ngIf="key % 2 ==0" (click)="get(key)">{{item}}</a><a *ngIf="key % 2 !=0" (click)="dynamic(key)">{{item}}</a></li>
</ul>

TS

import { Component, OnInit } from '@angular/core';
import { Router, NavigationExtras } from '@angular/router';@Component({selector: 'app-news',templateUrl: './news.component.html',styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {list: any[] = [];constructor(public router: Router) { }ngOnInit(): void {for (let i: number = 0; i<10 ; i++) {if(i%2 ===0){this.list.push("这是第"+i+"条新闻——get请求");}else{this.list.push("这是第"+i+"条新闻——动态路由");}}}dynamic(key): any{// 普通跳转,动态路由this.router.navigate(['/newsDetailDynamic/',key]);}get(key): any{// get 传值this.router.navigate(['/newsDetail'],{queryParams:{sid:key}});}
}

子路由—get请求参数接受
html

<h3>新闻详情——{{sid}}</h3>
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';@Component({selector: 'app-new-detail',templateUrl: './new-detail.component.html',styleUrls: ['./new-detail.component.scss']
})
export class NewDetailComponent implements OnInit {public sid : any;constructor(public route:ActivatedRoute) { }
// get请求ngOnInit(): void {console.log(this.route);this.route.queryParams.subscribe(data => {console.log(data.sid);this.sid = data.sid;});}
}

子路由—动态路由参数接受
html

<h3>新闻详情动态路由——{{sid}}</h3>

TS

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';@Component({selector: 'app-news-detail-dynamic',templateUrl: './news-detail-dynamic.component.html',styleUrls: ['./news-detail-dynamic.component.scss']
})
export class NewsDetailDynamicComponent implements OnInit {public sid : any;constructor(public route:ActivatedRoute) { }
// 动态路由请求ngOnInit(): void {console.log(this.route);this.route.params.subscribe(data => {console.log(data.sid);this.sid = data.sid;});}
}

讲一下上边的吧,主要是get请求携带参数和动态路由携带参数,然后子组件分别去接收相应的参数,这个demo就是讲这样的语法过程

get请求:https://www.baidu.com?name=1
动态路由:https://www.baidu.com/1

上边就是get请求和动态路由的区别,其实就是两种常规的web请求,不过在Angular中获取参数的方式不同罢了。

我是分割线

嵌套路由的话,就不贴demo了,因为嵌套的话涉及的组件比较多,主要是贴上来就比较长了,而且很简单,有兴趣的可以看我的github里的Angular-demo,自己直接运行一下,别忘了下载下来后加载Angular依赖。

结语

自此Angular的基本语法我已经探索的差不多了,当然这点东西对于学习前端的大拿肯定是远远不够的,只是基础中的基础,但是对于我这个主要做java的,已经足够了。如果观看中哪里有问题,随时留言,一起讨论一起成长!

Angular基础教程+Demo项目——尽可能全面一些——第二节相关推荐

  1. Angular 基础教程(7.0)

    课程亮点 按照初学者的学习路线规划内容 所有代码均采用 Angular 7.0 版本 覆盖日常开发中使用频率最高的特性 To B.To C 型界面,移动端 PWA 全面覆盖 附赠 3 个附录,对比 5 ...

  2. 保姆级的HTML零基础教程少见吧?这是第一节(1)

    作者简介 作者名:1_bit 简介:CSDN博客专家,2020年博客之星TOP5,蓝桥签约作者.15-16年曾在网上直播,带领一批程序小白走上程序员之路.欢迎各位小白加我咨询我相关信息,迷茫的你会找到 ...

  3. 2021最新HarmonyOS鸿蒙系统应用开发之基础入门教程到实战—持续更新(第二节:鸿蒙OS系统分布式操作)

    老罗带你了解鸿蒙,专注于移动端领域技术的研发和推广,助力鸿蒙在国内技术推广和普及. 每篇内容都有视频讲解,可直接点击观看+关注,持续更新中 2021最新HarmonyOS鸿蒙系统应用开发之基础入门教程 ...

  4. 代驾APP_第一章_项目环境搭建_第二节

    代驾APP_第一章_项目环境搭建_第二节 文章目录 代驾APP_第一章_项目环境搭建_第二节 1-11 创建bff-driver服务 一.创建项目 二.配置pom.xml文件 三.编写YML配置文件 ...

  5. Angular基础教程

    https://www.runoob.com/angularjs/angularjs-tutorial.html 教程文档 基本上学完这些,你就能正常的开发项目了,注意是正常开发而不是架构 阅读本教程 ...

  6. angular基础教程:快速开始

    好的工具可以使开发事半功倍. Angular CLI是一个命令行接口工具,我们可以用它创建项目.添加文件.测试.压缩捆绑(bundling)和部署等. 这一节的主要目标是使用Angular CLI构建 ...

  7. Angular *NgFor - angular 基础教程

    转载自 http://www.ngui.cc/news/show-115.html 在 Angular 中我们可以使用 ngFor 指令来显示数组中每一项的信息. 使用 ngFor 指令 更新 Mai ...

  8. Angular 事件_Angular $event - angular 基础教程 - Angular 教程网

    转载自 http://www.ngui.cc/news/show-113.html 获取鼠标事件 在第三节的示例中,假如我们需要获取鼠标事件,那应该怎么办呢?这时,我们可以引入 $event 变量,具 ...

  9. 《Python数据分析基础教程:NumPy学习指南:第二版》读书笔记

    内容 主要介绍了NumPy库中的函数. 组成方式 用非常零散的知识点串联成章节. 内容摘要 极简地展示了章节中所运用的函数. 第一章 arrange函数创建NumPy数组. 第二章 NumPy特性 在 ...

最新文章

  1. Docker1.12让容器使用和宿主机同一个网段
  2. 五分钟学会悲观乐观锁-java vs mysql vs redis三种实现
  3. 用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 (zz)
  4. python 32位和64位的区别在哪
  5. 历数2013年优秀的开源游戏引擎与开源游戏项目
  6. HTML解析利器HtmlAgilityPack
  7. python3.X 使用pip 离线安装whl包(转载)
  8. 客户端显示服务器图片不显示,客户端请求服务器图片不显示
  9. 领域应用 | 中医临床术语系统
  10. java.lang.NoSuchFieldError: No instance field
  11. UnrealScript语言基础
  12. 我的实例我做主--ECS运维必读
  13. Hadoop学习心得一
  14. 人工智能AI 生成的艺术:从文本到图像
  15. kangle配置cdn_kangle穿刺及cdn回源配置
  16. 我的健康我做主”芋头有奇特功效-抗…
  17. nodejs怎么看安装成功_教你怎么用XBOX ONE安装KODI看4K蓝光电影,并实现PC局域网共享...
  18. Pinbox 使用快捷键打开网页
  19. 在python用matplotlib库进行三维绘制
  20. mpu6050六轴传感器msp430驱动程序

热门文章

  1. 常见的销售方式有哪些
  2. 正则表达式详解 js
  3. 阿里云服务器中挖矿病毒解决办法(已实践)
  4. Excel中通过数据有效性限制身份证长度
  5. IK Analyzer 热更新自定义词典
  6. AddressSanitizer原理解析
  7. JQuery报错:Uncaught TypeError
  8. 《Long-Term Temporal Convolutions for Action Recognition》 论文翻译
  9. 【不仅仅是程序员】——对自己好点!(3)
  10. 南大计算机专业考研2019分数,2021南京大学研究生分数线是多少