Angular

1.Angular

简单对比三大框架

框架名称AngularReactVue
优点1.良好的应用程序结构
2.双向数据绑定
3.指令、HTML模板
4.可嵌入、注入、测试…
1.速度快、模块化
2.跨浏览器、兼容性好
1.简单易学
2.异步更新DOM,速度快
3.组件复用高效…
缺点1.入门容易,深入难
2.官方文档基本只有api,无示例
React(V)+ReactRouter+Flux才能构成完整应用1.新生儿,生态不够成熟
2.有关Vue的三方库较少
使用情况较少最多较少

2.环境搭建

2.1安装node.js、npm
npm install -g cnpm --registry=https://registry.npm.taobao.org # cnpm可以更快下载包,推荐安装
2.2安装脚手架
npm install -g @angular/cli
2.3创建项目
ng new demo
2.4编译打开运行
ng serve --open
2.5项目结构介绍
  • src
    • app:组件和根模块
    • karma.config.js:端到端测试文件
    • polyfills.js:填充库,需要添加 (window as any).global = window
// app.module.ts

// 这个文件时angular的根模块,告诉angular如何组装应用
import { BrowserModule } from '@angular/platform-browser'; // 浏览器解析模块
import { NgModule } from '@angular/core'; // angular核心模块
import { AppComponent } from './app.component'; // 根组件
// NgModule装饰器,接受一个对象,告诉angular如何编译和启动应用
@NgModule({
  declarations: [ // 配置当前模块运行的组件 
    AppComponent // 根组件
  ],
  imports: [
    BrowserModule // 当前项目依赖的其他模块
  ],
  providers: [],// 配置当前项目所需要的其他服务
  bootstrap: [AppComponent] // 指定应用的主视图(根组件),通过引导根AppModule来启动应用,一般是根组件
})
// 不需要暴露任何东西,因为没有模块引用根组件
export class AppModule { }
// app.component.ts

// 引入核心模块的component
import { Component } from '@angular/core';
@Component({
  selector: 'app-root', // 组件的名称
  templateUrl: './app.component.html', // html
  styleUrls: ['./app.component.scss'] // css
})
export class AppComponent {
  title = 'demo1'; // 暴露根组件
}
2.6创建自定义组件

会在app/components/目录下创建news文件夹,包含组件的HTML、style、ts等文件

ng g component components/news
// app.module.ts

import { NewsComponent } from './components/news/news.component' // 引入自定义组件
@NgModule({
  declarations: [ // 配置当前模块运行的组件 
    AppComponent, NewsComponent
  ],
  // ...
})
// 然后在其他组件的HTML使用<app-news></app-news>即可
<!--app.component.html-->
<app-news></app-news>
<!--...-->

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QAkE1kBD-1608216905832)(image-20201215230155951.png)]

3.基本语法

3.1动态属性
<!-- [src]是动态属性,类似Vue中的 :src -->

<img class ="search" [src]="picUrl" alt="google" width="80px" height="32px">
3.2ngFor、ngSwitch
<!--ngFor、ngSwitch、ngIf、ngClass的用法-->

<!--ngFor用法-->
<div *ngFor="let item of lists;let key=index"> <!--lists是该组件的ts类中的属性,可以直接读取到,下同-->
    <h4>{{item.title}}</h4>
    <span style="color: lightcoral;">[{{key}}]</span>
    <p>{{item.content}}</p>
</div>

<!--ngIf用法-->
<div *ngIf="showMore">
    <h4>Common</h4>
</div>

<!--ngSwitch用法-->
<div [ngSwitch]="clickCount">
    <div *ngSwitchCase="1">你居然打老子一巴掌</div>
    <div *ngSwitchCase="2">你居然又打老子一巴掌</div>
    <div *ngSwitchCase="3">你滚!</div>
    <div *ngSwitchDefault>你还没挨老子!</div>
</div>

<!--ngClass、ngStyle用法-->
<div [ngSwitch]="clickCount" [ngClass]="{'red': clickCount===3}" [ngStyle]="{'font-size': (clickCount*3+16)+'px'}">
</div>
3.3管道
<!--管道用于对数据进行格式化,比如对一个obj使用json管道,就可以在前端页面以json格式显示,最常用处理时间格式-->

<span style="color: lightcoral;">{{today|date:'yyyy/MM/dd HH:mm:ss'}}</span>
<!--{{ obj | json }}-->
3.4事件
<!--点击事件用法-->
<button (click)="loadMore($event)">Load more</button>
<!--keydown keyup 等等-->
3.5双向数据绑定
// 双向数据绑定需要用到FormsModule模块,因此需要先引入,才能使用

// app.module.ts
import { FormsModule} from '@angular/forms'
@NgModule({
  // ...
  imports: [
    BrowserModule,FormsModule // 当前项目依赖的其他模块
  ],
  // ...
})
 <input type="text" [(ngModel)]="keywords">-{{keywords}}
3.6服务

类似于Vuex或Mixin,封装了多个组件公共使用的东西

ng g service services/store
// app.module.ts 引入并配置服务
import { StoreService } from './services/store.service'; // 根组件
@NgModule({
  // ...
  providers: [StoreService],// 配置当前项目所需要的其他服务
  // ...
})

// 例如 home 组件需要用(home.component.ts)
import { StoreService } from '../../services/store.service'; // 先引入
export class HomeComponent implements OnInit {
  // ...
  constructor(public store: StoreService) { // 使用public,在类其他地方就可以直接使用了
    console.log(store);// 官方推荐使用
  }
  ngOnInit(): void {
    // 这个是在指令和组件初始化完成,并不是DOM加载完成
  	// 页面每次刷新都会调用这个函数
  }
  // ...
}
3.7DOM操作
  • 原生操作DOM(当然不建议)

    <!--home.component.html-->
    <div id="box1" *ngIf="xxx">
      这个box在ngOnInit()是获取不到的!
    </div>
    
    // home.component.ts
    ngOnInit(): void {
        // 这个是在指令和组件初始化完成,并不是DOM加载完成
      	// 页面每次刷新都会调用这个函数
    }
    ngAfterViewInit():void{
        // 这里才可以拿到所有的HTML元素(建议在这里操作DOM)
        let box:any = document.getElementById('box1')
    }
    
  • @ViewChild操作DOM

    <!--home.component.html,需要给box设置#box-->
    <div  #box>
        <h2>您好,angular!</h2>
    </div>
    
    @ViewChild('box') box:any // 拿到id是box的HTML元素,并赋值给box
    ngAfterViewInit():void {
        console.log(this.box);
        this.box.nativeElement.style.letterSpacing='2px'
    }
    
3.8父子组件通信
  • (子调父)@Input:使得父组件不仅可以给子组件传值,还可以把父组件的方法、甚至父组件传给子组件

    <!--home.component.html-->
    <app-news #homeNews [title]='title' [homeFun]='test' [homeComp]='this'></app-news>
    
    // news.component.ts
    export class NewsComponent implements OnInit {
      @Input('title') title:any;
      @Input('homeFun') homeFun:any;
      @Input('homeComp') homeComp:any
      // ...
      ngAfterViewInit():void{
        this.box.nativeElement.style.letterSpacing='2px'
        this.homeFun() // 调用home组件方法
        console.log(this.homeComp); // 父组件
      }
      // ...
    
  • (父调子)@ViewChild()

    <!--home.component.html-->
    <app-news #homeNews></app-news>
    
    // home.component.ts
    @ViewChild('homeNews') news: any // 拿到子组件 news 
    ngAfterViewInit(): void {
        console.log(this.news.test()); // 逻辑处理
    }
    
3.9生命周期函数
  • ngOnInit():用来请求数据

  • ngAfterViewInit():DOM操作

  • ngOnDestroy():离开某页面保存数据

3.10异步编程(Rxjs)

RxJS是一个异步编程的库,同时它通过observable序列来实现基于事件的编程(类似于Promise,但是比它更强大)

  • 简单使用:先写一个request服务,然后组件调用

    // request.service.ts(服务需要先在根组件引入和注册)
    import { Injectable } from '@angular/core';
    import { Observable } from 'rxjs' // 1.引入类
    @Injectable({
      providedIn: 'root'
    })
    export class RequestService {
      constructor() { }
      getRxjsData(): any {
        // 2.实例化一个对象,并写逻辑
        return new Observable((observer: any) => {
          setTimeout(() => {
            var data = {
              name: 'yuwan',
              age: 22
            }
            observer.next(data) // 成功调用
            // observer.error(msg) 失败调用
          }, 2000)
        })
      }
    }
    
    // home.component.ts
    import { RequestService } from '../../services/request.service'; // 引入服务
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.scss']
    })
    export class HomeComponent implements OnInit {
      // ...
      constructor(public request: RequestService) {
      }
      ngOnInit(): void {
        var resp=this.request.getRxjsData() // 请求数据
        resp.subscribe((data)=>{
          console.log(data); // 获取数据
        })
      }
      // ...
    }
    
  • 取消订阅:即撤销发送请求(Promise是无法实现的)

    // ...
    var opt=resp.subscribe((data)=>{
          console.log(data);
    })
    opt.unsubscribe() // 取消逻辑,例如一秒后取消发送
    
  • 多次执行:订阅后,可多次执行(Promise是无法实现的)

    // request.service.ts 
    getRxjsData(): any {
        return new Observable((observer: any) => {
          let count=0
          setInterval(() => {
            count++
            observer.next(count) // 成功调用
            // observer.error(msg) 失败调用
          }, 2000)
        })
      }
    
    // ...
    var opt=resp.subscribe((data)=>{
          console.log(data); // 会2秒执行一次
    })
    // ...
    
  • 处理数据:如上所示,如果要打印2,4,6…,需要处理数据(管道)

    import { map, filter } from 'rxjs/operators'
      ngOnInit(): void {
        var resp = this.request.getRxjsNum() // 先设置管道过滤再打印数据,filter、map 
        resp.pipe(filter((val: any) => {
          if (val % 2 == 0) {
            return true
          }
        })).subscribe(data => {
          console.log(data);
        })
    }
    
3.11数据交互(和服务器打交道)

angular可通过自带与服务器交互的模块HttpClientModulejsonp(可解决跨域)axios第三方库等方式

jsonp原理:大概是传一个回调函数去服务端,然后执行拿到数据后,再返回,url格式如http://www.xxx.com/api/goodslist?callback=xxx

// app.module.ts
import { HttpClientModule,HttpClientJsonpModule} from '@angular/common/http' // 引入
@NgModule({ 
   // ...
  imports: [
    HttpClientModule,HttpClientJsonpModule // 当前项目依赖的其他模块
  ],
	// ...
})
// home.component.ts
import { HttpClient,HttpHeaders } from '@angular/common/http' // 引入这个服务
export class HomeComponent implements OnInit {
  // ...
  constructor(public http:HttpClient ) {} // 实例化
  getData():void{ // get方法
    this.http.get('http://a.itying.com/api/productlist').subscribe(data=>{
      console.log(data);
    })
  }
  postData(): void { // post方法
    var headOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json'
      })
    }
    this.http.post('url', { username: 'yuwan', password: '123456' }, headOptions).subscribe(...)
  }
  getJsonPData(): void { // jsonp方式,其中第二个参数:cb或者callback 由服务端决定
    this.http.jsonp('url', 'callback').subscribe(resp => {
      console.log(resp);
    })
  }
 // ...
}
3.12路由

创建项目时,选择安装路由,基本只需要在routes里更改,然后自定义组件即可

<style>
.router-link-active{
  color:red
}
</style>
<!--导航链接 -->
<span style="margin-left:5px"><a [routerLink]="['/home']"  routerLinkActive="router-link-active"  >Home</a></span>
<span  style="margin-left:5px"><a [routerLink]="['/about']" routerLinkActive="router-link-active" >about</a></span>
// app-routing.module.ts
import { HomeComponent } from './components/home/home.component';
import { AboutComponent } from './components/about/about.component';
const routes: Routes = [
  {
    path: 'home', 
    component: HomeComponent
  },
  {
    path: 'about', 
    component: AboutComponent
  },
  { // 匹配不到路由的时候,默认重定向到 home
    path: '**', 
    redirectTo: 'home'
  },
];

普通路由传参

<!--home.component.html-->
<a [routerLink]="['/news']"  [queryParams]='{aid:123}'>点我跳转</a>
// news.component.ts
import { ActivatedRoute } from '@angular/router'
export class NewsComponent implements OnInit {
  constructor(public activeRoute: ActivatedRoute) { }
  ngOnInit(): void {
    this.activeRoute.queryParams.subscribe(data => {
      console.log(data);
    })
  }
}

动态路由传参

<!--home.component.html-->
<a  [routerLink]="['/news/',123]" >点我跳转</a> <!--传送参数-->
// app-routing.module.ts
const routes: Routes = [
	// ...
  {
    path: 'news/:aid', 
    component: NewsComponent
  }
    // ...
];

// news.component.ts
export class NewsComponent implements OnInit {
  constructor(public activeRoute: ActivatedRoute) { }
  ngOnInit(): void {
    this.activeRoute.params.subscribe(data=>{ // 接收参数
      console.log(data);
    })
  }
}

普通路由跳转和动态路由跳转

import { Router,NavigationExtras } from '@angular/router'
export class NewsComponent implements OnInit {
  // ...
  jump():void{ 
     this.router.navigate(['/news/','1234']) // 动态路由跳转
     this.router.navigate(['/home']) // 普通路由跳转
  }
  jump2():void{ // get方式跳转
      let queryParams:NavigationExtras={
      queryParams:{
        'aid':'1233'
        }
       }
      this.router.navigate(['/news'],queryParams)
  }
}

嵌套路由

先创建相关组件,再修改app-routing.module.ts

ng g component components/service/request
ng g component components/service/state
// app-routing.module.ts
import { ServiceComponent } from './components/service/service.component';
import { RequestComponent } from './components/service/request/request.component';
import { StateComponent } from './components/service/state/state.component';
{
    path: 'service',
    component: ServiceComponent,
    children: [
      {
        path: 'request',
        component: RequestComponent
      },
      {
        path: 'state',
        component: StateComponent
      }
    ]
},
<!--home.component.html--> 
<a [routerLink]="['/service/request']">跳转request</a>
<a [routerLink]="['/service/state']"  >跳转state</a>
<div>
    <router-outlet></router-outlet>
</div>
Logo

前往低代码交流专区

更多推荐