谷歌開源的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 })