谷歌开源的JavaScript库,性能比以前最早的版本提高不少,采用Typescript进行,以及新的模式进行开发,因此从第二版本开始,忽然大幅降低人数。javascript
技术:typescript的基本使用,es6css
Typescript是JavaScript超集,JavaScript内容和es6均可以直接在typescript中使用。html
Typescript的代码依然要编译成纯JavaScript,typescript编译工具能够运行在任何的服务器和任何系统上。Typescript开源vue
Typescript:java
1、很是包容,JavaScriptios
2、定义简单到复杂的一切类型。es6
3、typescript若是报错,依然能够生成JavaScript文件typescript
4、typescript拥有活跃的社区。npm
Typscript缺点:编程
安装typescript
cnpm install -g typescript
建立后缀为。ts的文件,最后须要经过编译转成js
将TS文件编译成js
tsc index.ts
安装Angular-cli
cnpm install -g @angular/cli
建立项目
ng new angularApp --skip-install
安装模块
npm install
启动开发服务命令
Npm start
启动时候打开浏览器
ng serve --open
建立组件命令
ng g component component/news
组件使用:
<app-news></app-news>
原始数据类型:布尔,数值,字符串,null,undefined;
布尔类型定义:注意直接调用Boolean是能够的
let isDone:boolean = true; isDone = false; let isCheck:boolean = Boolean(1)
错误方式:由于new Boolean返回的是1个对象类型
let isCheck:boolean = new Boolean(1)
数值类型定义
let num:number = 1; let num16:number = 0xf00a; let notNum:number = NaN; let infNum:number = Infinity;
字符串类型定义
let username:string = 'laochen'; let age:number = 30; let juzi:string = `个人年龄是${age}`;
空值:大部分状况下用于定义函数没有返回值,通常不用于定义变量,由于一旦变量定义为void类型,那么就只能赋值undfined,null;
//空值 function hello():void{ console.log('helloworld') } let unable:void = undefined; unable = null;
Null和undefined定义
//null和undefined类型,意义不大 let a:undefined = undefined; a = null; let b:null = null; b = undefined;
注意:null和undefined是全部类型的子类型,void类型是不能赋值给其余类型的,虽然它也只有undefined和null,例如
let username:string = 'laochen'; username = undefined; let abc:undefined = undefined; let cba:void = undefined; username = abc; //username = cba;//这是不容许,由于cba是void类型 let age:number = 30;
任意值类型(any)用来表示容许任意值类型赋值。
//任意值类型 let admin:any = 'adbc' admin = 123; //任意值类型容许访问他任意的属性 let anything:any = 'hello'; console.log(anything.myname);
未申明类型的变量
let something1; //something1在声明时候未定义类型,也没有赋值,就会被定义为任意值类型 something1 = 'abc'; something1 = 123;
类型推断
//something2在声明的时候虽然未定义类型,可是因为赋值为字符串,typescript有类型推断规则,会将赋值的类型定义成变量的类型 let something2 = 'abc'; //something2 = 123;//会报错
联合类型:表示取值能够取多个类型。
let cat:string|number; cat = '小猫咪'; cat = 1; let cat1:string|number = '小猫咪';
什么是接口?行为的抽象。具体行动须要由类去实现(接口抽象出来的内容)。
至关于定义类的描述。
定义:
interface Person{ name:string; age:number; } let tom:Person = { name:"tom", age:16, } //约束TOM这个对象,必须和接口一致属性。 //通常接口的首字母大写。 //用接口定义的对象,属性不能多写,也不能少写
接口可选属性:该属性可写,可不写,但不能多写属性,加?便可
//接口属性可选 interface Student{ name:string; age?:number; } let s1:Student = { name:"小明", age:16, }
接口可定义任意的属性
//任意属性 interface Teacher{ name:string; age?:number; [propName:string]:any; } let t1:Teacher={ name:"老王", age:35, school:'清华' }
只读属性,readonly
interface Cat{ //只读属性,只能进行1次赋值,后面不能够在修改,可是能够获取 readonly name:string; color:string; age:number; } let c1:Cat = { name:'波斯猫', color:"白色", age:10 } //c1.name = '中华猫'; //会报错,由于c1.name是只读属性
typescript会对函数的输入和输出有约束,
输入和输出会定义类型,参数传入(参数定义类型),返回值(定义类型)
//typescript会对函数的输入和输出有约束, //输入和输出会定义类型,参数传入(参数定义类型),返回值(定义类型) function sum1(x:number,y:number) :number{ return x+y; } let result:number = sum1(3,4);
函数表达式写法
//函数表达式写法 let sum2 = function(x:number,y:number) :number{ return x+y; } //这种写法,实质上仅将右侧匿名函数进行了类型的定义。对左边sum2这个变量没有实质的定义; let sum3:(x:number,y:number) => number = function(x:number,y:number) :number{ return x+y; }
可选参数,加?
//可选参数 function sumName(firstname:string,lastname?:string):string{ return firstname+lastname; } sumName('lao',"chen"); sumName('lao'); //注意:可选参数必须放置到必须参数的后面,可选参数后面不容许放置必需要的参数 //不容许 // function sumName2(lastname?:string,firstname:string,):string{ // return firstname+lastname; // }
参数默认值
//默认参数 function sumName3(firstname:string='chen',lastname:string='guan'):string{ return firstname+lastname; }
剩余参数
arguments
来访问全部传入的参数。
//剩余参数 //ES6正常模式 function fnpush(...items){ } function fnpush1(...items:any[]):string{ return 'abc'; }
重载
//重载 //重载容许1个函数,接收不一样数量或者类型的参数 function setAbc(x:number|string):number|string{ return x; } function fnAbc(x:boolean):boolean; function fnAbc(x:number):number; function fnAbc(x:string):string; function fnAbc(x:any):any{ if(typeof x==='number'){ return x; }else{ return x } } fnAbc('1') fnAbc(false)
类
//定义静态方法 class Animal{ static isAnimal(a){ return a instanceof Animal; } } let dog = new Animal(); Animal.isAnimal(dog); //typescript静态属性 class Dog{ static age =20; } console.log(Dog.age) //类属性 class Abc{ a = 1; b = 3; private c = 4; constructor(){ this.a = 1; this.b = 2; this.c = 3; } } //属性能够有3种访问的修饰符进行修饰,public/private/protect //public,任何地方均可以访问,默认全部的属性都是public //private,私有的,只能在类的内容访问,不能类外面访问 //protected,受保护的,protect在子类里能够访问,private是不容许的 class Banana{ private name; public constructor(name){ this.name = name; } } let aa = new Banana('海南香蕉'); //console.log(aa.name)//不能获取,name是私有属性 //aa.name = '巴黎香蕉' //不能访问,name是私有属性 class Apple{ protected name; public constructor(name){ this.name = name } } //protect在子类中容许访问。 class BigApple extends Apple{ private constructor(name){ super(name) console.log(this.name) } } //若是构造函数式私有的将不能实例化 //let bb = new BigApple('aaaa'); //抽象类,抽象类不容许实例化,通常用于继承实现。 abstract class PinkPig{ public name; constructor(name){ this.name = name } //只定义,不实现 public abstract sayHi(); } class SmallPinkPig extends PinkPig{ sayHi(){ console.log("helloworld") } }
注意:Componet.css仅用于组件,src根目录下的style.css全局的样式
MVVM设计模式起源于MVC。
V->view:视图
C->控制器:交互修改数据的方式
M->model
V->view
VM -> 对数据和视图的双向绑定,只要修改数据,vm(框架)就会自动改变视图,视图的交互改变了数据。
语法:{{ ...变量和表达式}}
应用:应用于html内容里,也能够应用于property里
<h1 [innerHtml]="htmlStr"></h1>
定义的class三种方式,跟VUE一致,会自动的将变量和原有的HTML的CLASS相加
<!-- 定义变量的方式 --> <h1 class="abc" class="{{classStr}}">class1</h1> <h1 class="abc" [class]="classStr">class2</h1> <h1 [attr.class]="classStr">class3</h1>
Class变量类型
<!-- 变量类型 --> <!-- 字符串模式 --> <h1 [class]="classStr">class4</h1> <h1 class="a" [class]="'str abc'">class4</h1> <!-- 对象模式 --> <h1 [class]="classObj">class5</h1> <h1 [class]="{bgBlue:isShow}">class6</h1> <!-- 数组模式 --> <h1 [class]="['bgBlue','active','abc']">class7</h1> <h1 [class]="classArr"></h1>
Style
<!-- style --> <!-- style表达式类型 --> <!-- 字符串变量 --> <h1 [style]="styleStr"></h1> <!-- 对象模式 --> <h1 [style]="styleObj"></h1> <!-- 橙色 --> <h1 [style.height]="styleObj.width">h</h1> <h1 [style.width]="colorAbc"></h1> <h1 [style.width.px]="widthNum"></h1>
事件
<!-- 绑定事件: 由等号左侧写小括号加上事件名称,右边写调用的事件函数 --> <button (click)="changeColor()">改变颜色</button> <button (click)="changeButton($event)">改变颜色</button>
上面用到的练习代码
isShow = true; classArr = ['abc','cba','aaa']; styleStr = "background:skyblue;width:400px;height:400px;"; styleObj = { background:"pink", width:'100px', height:"100px" }; colorAbc='100px'; widthNum = 200; changeColor(){ this.styleObj = { background:"purple", width:'200px', height:"300px" }; } changeButton(event){ console.log(event) event.target.style.background = 'green' }
条件渲染
<!-- 条件渲染 --> <!-- person若是是广东人,就显示广东人的疫情信息 --> <div *ngIf="person=='广东人'"> 广东:1000人 </div> <div *ngIf="person=='湖北人'"> 湖北:40000人 </div> <button (click)="togglePerson()">切换身份</button> <h1>style的条件渲染</h1> <!-- 这里使用的条件渲染,会移除出Document,添加进DOM都会消耗性能。 --> <!-- 使用STYLE进行条件渲染,若是须要频繁切换内容,那么须要style完成条件渲染--> <div [style.display]="person=='广东人'?'block':'none'"> 广东:1000人 </div> <div [style.display]="person=='湖北人'?'block':'none'"> 湖北:40000人 </div> <!-- 条件渲染,匹配多种状况 --> <div [ngSwitch]="homeState"> <div *ngSwitchCase="'睡觉'">卧室</div> <div *ngSwitchCase="'看电视'">客厅</div> <div *ngSwitchCase="'吃饭'">餐厅</div> <div *ngSwitchCase="'发呆'">阳台</div> <div *ngSwitchDefault>厕所</div> </div> <!-- 条件渲染,匹配多种状况 --> <div [ngSwitch]="orderState"> <div *ngSwitchCase="1">待付款</div> <div *ngSwitchCase="2">已付款</div> <div *ngSwitchCase="3">发货</div> <div *ngSwitchCase="4">已收货</div> <div *ngSwitchDefault>丢失</div> </div>
循环渲染
<!-- 列表循环 --> <ul> <li *ngFor="let item of arr">{{item}}</li> </ul> <!-- 列表循环获取索引值 --> <ul> <li *ngFor="let item of arr;let i=index">索引值:{{i}};内容:{{item}}</li> </ul> <!-- 将列表的内容传入事件 --> <ul> <li *ngFor="let item of arr;let i=index" (click)="choosePerson(item,i)">索引值:{{i}};内容:{{item}}</li> </ul> <!-- 循环复杂数组 --> <ul> <li *ngFor="let item of students;let key=index">{{key}}-{{item.name}}的爱好是{{item.hobby}}</li> </ul>
导入模块至app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; //导入form模块 import { FormsModule} from '@angular/forms' import { AppComponent } from './app.component'; import { NewsComponent } from './views/news/news.component'; @NgModule({ declarations: [ AppComponent, NewsComponent ], //导入 imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
表单的数据绑定
<input type="text" [(ngModel)]="username">
设置临时变量绑定DOM对象
<!-- 表单数据获取 --> <div> <label for="">用户名</label> <input #input1 type="text" > </div> <div> <label for="">密码</label> <input #input2 type="text" > </div> <button (click)="getContent(input1.value,input2.value)">获取帐号密码</button>
NgForm获取整个表单的数据,NgForm只能用在表单内
<form action="" #formobj> <input type="text" [(ngModel)]="username" name="username" > <input type="text" [(ngModel)]="password" name="password" > <button (click)='eventFn(formobj)'>按钮</button> </form>
管道(跟vue过滤器相似)
将对象转换成json格式显示 <h1>{{student | json}}</h1> 将时间转化yy/MM/dd格式 <h1>显示时间:{{time | date:"yy/MM/dd"}}</h1> 转全大写 <h1>用户名: {{username | uppercase}} </h1> //管道能够转换屡次 <h1>{{'abcdefg'|uppercase|lowercase}}</h1>
自定义管道
建立自定义的管道文件
ng g pipe filter/lcUppercase
import { Pipe, PipeTransform } from '@angular/core'; // @Pipe({ // name: 'lcUppercase' // }) // export class LcUppercasePipe implements PipeTransform { // transform(value:string,...args:string[]):string { // if(value=="老陈"){ // return "大帅哥老陈" // } // return value ; // } // } @Pipe({ name: 'lcUppercase' }) export class LcUppercasePipe implements PipeTransform { transform(value:string,...args:string[]):string { console.log(args) return '¥'+value+args[0]; } }
模板
注意:msg是模板变量,lcUppercase是转换函数,:后面是参数
<h1>{{msg|lcUppercase:'元'}}</h1> //msg=100 //根据上面的自定义管道获得的结果是 ¥100元
//在父组件(html)中传参 <app-child [item]="sendchildMsg"></app-child> //父组件中的(ts)值 sendchildMsg ="这是给子元素的数据,但愿在子组件中显示"; //子组件导入Input import {Input} from '@angular/core'; export class ChildComponent implements OnInit { //@input的做用是定义模块输入,是用来让父级组件向子组件传递内容。 @Input() item; } //子组件(html) <h1>{{item}}</h1> //显示的结果是:这是给子元素的数据,但愿在子组件中显示
//子组件模板(.html) <button (click)="sendMsg()">发送消息给父组件</button> //子组件逻辑(.ts) //Output用于把一个类字段标记为输出属性,并提供配置元数据。 凡是绑定到输出属性上的 DOM 属性,Angular 在变动检测期间都会自动进行更新。 //angular提供了EventEmitter用来触发自定义事件。子指令建立一个 EventEmitter 实例,并将其做为输出属性导出。子指令调用已建立的 EventEmitter 实例中的 emit(payload)方法来触发一个事件,父指令经过事件绑定(eventName)的方式监听该事件,并经过 $event 对象来获取payload对象。 //导入 import {Output,EventEmitter } from '@angular/core'; export class ChildComponent implements OnInit { //实例化 @Output() childMsg=new EventEmitter() //自定义事件 sendMsg(){ this.childMsg.emit({msg:"我子组件,这是我发给父组件的消息"}) } } //父组件模板 <h1>子组件发来信息:{{getChildMsg}}</h1> //监听事件,childMsg自定义 <app-child (childMsg)="getEvent($event)"></app-child> //父组件逻辑 export class AppComponent { getChildMsg=""; getEvent(event){ console.log(event) this.getChildMsg = event.msg } }
生命周期函数
constructor(){ console.log("组件构造函数调用") } ngOnChanges(){ console.log("数据发生变化之时就会调用此函数ngOnChanges") } ngOnInit(){ console.log("第一次显示数据绑定和指令输入属性以后,就会调用,只调用一次") } ngDoCheck(){ console.log('在ngOnChanges和ngOnInit发生以后,会进行一次检测') } ngAfterContentInit(){ console.log('数据内容渲染到视图上以后') } ngAfterContentChecked(){ console.log('数据内容渲染到视图检测以后') } ngAfterViewInit(){ console.log('完成组件和子组件初始化') } ngAfterViewChecked(){ console.log('完成组件和子组件初始化检测后') } ngOnDestory(){ console.log("销毁组件") }
自定义指令
建立指令文件:
ng g directive directive/lcstyle
设置指令内容和功能
//父组件 <h1 [appLcstyle]="'abc'"></h1> //ElementRef 顾名思义是元素参阅。 其实在实际应用中就是获取视图层的dom元素,借助Augular提供的依赖注入机制,轻松的访问到dom元素。 //子组件Directive import { Directive,Input,ElementRef } from '@angular/core'; //自定义指令 @Directive({ selector: '[appLcstyle]' }) export class LcstyleDirective { @Input() appLcstyle; constructor(public ref:ElementRef) { console.log('ref') //会输出dom元素 } //生命周期函数 ngOnChanges(){ //console.log(this.appLcstyle) //console.log(this.ref) this.ref.nativeElement.className = this.appLcstyle; this.ref.nativeElement.innerHTML = this.appLcstyle; this.ref.nativeElement.addEventListener("click",()=>{ this.ref.nativeElement.style.background="pink" }) } }
自定义服务:不少组件须要共用的功能抽象出来(类和函数)
一、建立服务文件
ng g service service/stocklist
服务
import { Injectable } from '@angular/core'; import axios from 'axios' @Injectable({ providedIn: 'root' }) export class StockListService { constructor() { } async getAllStocks(){ let httpUrl = 'http://localhost:8080/stocklist'; let result = await axios.get(httpUrl); return result.data.data; } async superStocks(){ let httpUrl = 'http://localhost:8080/superStock'; let result = await axios.get(httpUrl); return result.data.data; } }
二、导入服务到项目中
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { LcstyleDirective } from './directive/lcstyle.directive'; //将服务导入到项目中 import { StockListService } from './service/stock-list.service' @NgModule({ declarations: [ AppComponent, LcstyleDirective ], imports: [ BrowserModule ], //导入服务 providers: [ StockListService ], bootstrap: [AppComponent] }) export class AppModule { }
使用服务获取数据
import { Component } from '@angular/core'; import axios from 'axios'; import {StockListService} from './service/stock-list.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'angularapp'; stockList = [] superStocks = [] //注入服务 constructor( public stockSer:StockListService ){ // let httpUrl = 'http://localhost:8080/stocklist'; // axios.get(httpUrl).then((res)=>{ // console.log(res.data) // this.stockList = res.data.data.slice(0,10) // console.log(this.stockList) // }) stockSer.superStocks().then((res)=>{ this.superStocks = res.slice(0,10) }) } async stockFn(){ console.log(123) let allStocks = await this.stockSer.getAllStocks() this.stockList = allStocks.slice(0,10) } }
页面
<button (click)="stockFn()">获取10股票列表</button> <h1>预估今日涨停的十只股票</h1> <div *ngFor="let item of superStocks"> <h1>股票名称:{{item.stockName}}</h1> <h2>股票代码:{{item.stockCode}}</h2> <div class="img"> <img src="{{item.dailyChart}}" alt=""> <img src="{{item.hourlyChart}}" alt=""> </div> </div> <h1>普通股票</h1> <div *ngFor="let item of stockList"> <h1>股票名称:{{item.stockName}}</h1> <h2>股票代码:{{item.stockCode}}</h2> <div class="img"> <img src="{{item.dailyChart}}" alt=""> <img src="{{item.hourlyChart}}" alt=""> </div> </div>
路由配置
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import {IndexComponent} from './view/index/index.component'; import {AboutComponent} from './view/about/about.component'; import {NewsComponent} from './view/news/news.component' //配置路由对象 const routes: Routes = [ { //不须要加/ path:"", component:IndexComponent }, { path:'about', component:AboutComponent }, { path:"news", component:NewsComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
HTML模板
<!-- 根据路径的变化,显示不一样组件 --> <style> div>span{ margin: 20px; padding: 5px 10px; background-color: skyblue; } </style> <div> <span [routerLink]="['/']" routerLinkActive="router-link-active" >首页</span> <span [routerLink]="['/about']" routerLinkActive="router-link-active" >about</span> <span [routerLink]="['/news']" routerLinkActive="router-link-active" >news</span> </div> <router-outlet></router-outlet>
动态路由
{ //动态路由 path:"news/:id", component:NewsComponent },
获取动态路由的参数
import { Component, OnInit } from '@angular/core'; //导入route import {ActivatedRoute} from '@angular/router' @Component({ selector: 'app-news', templateUrl: './news.component.html', styleUrls: ['./news.component.less'] }) export class NewsComponent implements OnInit { title = "" //注入route constructor(public route:ActivatedRoute) { //http://localhost:4200/news/123?search=meinv#abc //console.log(this) } ngOnInit(): void { //console.log(this) //let params = this.route.params; //console.log(params.value.id); } goParams(){ //使用参数 this.route.params.subscribe((params)=>{ console.log(params) this.title = params.id; }) } }
子路由
{ path:'admin', component:AdminComponent, children:[ { path:'user', component:UserComponent }, { path:'product', component:ProductComponent } ] },
HTML模板设置
<p>admin works!</p> <style> .admin{ display: flex; height: 600px; } .admin .left{ width: 200px; background: skyblue; } .admin .main{ flex:1; background: lavenderblush; } </style> <div class="admin"> <div class="left"> 这是侧边栏 <div [routerLink]="['/admin/user']" routerLinkActive="router-link-active" >user</div> <div [routerLink]="['/admin/product']" routerLinkActive="router-link-active" >product</div> </div> <div class="main"> <router-outlet></router-outlet> </div> </div>
编程式导航,JS如何控制路由的跳转
1/依赖注入router
import { Component, OnInit } from '@angular/core'; //导入route,router import {ActivatedRoute,Router} from '@angular/router' @Component({ selector: 'app-news', templateUrl: './news.component.html', styleUrls: ['./news.component.less'] }) export class NewsComponent implements OnInit { title = "" //注入route,router constructor(public route:ActivatedRoute,public router:Router) { //http://localhost:4200/news/123?search=meinv#abc console.log(this) this.route.data.subscribe((data)=>{ console.log(data) this.title = data.msg }) } ngOnInit(): void { //console.log(this) //let params = this.route.params; //console.log(params.value.id); } goParams(){ this.route.params.subscribe((params)=>{ console.log(params) this.title = params.id; }) } goHome(){ //第一个参数是传入数组(路径的数组) this.router.navigate([''],{ queryParams:{ usernam:"admin" }, fragment:"abc", replaceUrl:true }) } }
//第一个参数是传入数组(路径的数组),自动拼接成完整的路径 this.router.navigate([''],{ //拼接参数 queryParams:{ usernam:"admin" }, fragment:"abc",//传hash值 //是否是要替换当前的页面 replaceUrl:true })