摘要:下面我們看看如果使用是什么樣子的,首先我們需要在組件的修飾器中配置,然后在組件的構(gòu)造函數(shù)中使用參數(shù)進(jìn)行依賴注入。
第一節(jié):Angular 2.0 從0到1 (一)
第二節(jié):Angular 2.0 從0到1 (二)
第三節(jié):Angular 2.0 從0到1 (三)
在 hello-angularsrcapploginlogin.component.ts 中更改其模板為下面的樣子
import { Component, OnInit } from "@angular/core"; @Component({ selector: "app-login", template: ``, styles: [] }) export class LoginComponent implements OnInit { constructor() { } ngOnInit() { } }
我們增加了一個(gè)文本輸入框和一個(gè)按鈕,保存后返回瀏覽器可以看到結(jié)果
接下來我們嘗試給Login按鈕添加一個(gè)處理方法 。(click)表示我們要處理這個(gè)button的click事件,圓括號是說發(fā)生此事件時(shí),調(diào)用等號后面的表達(dá)式或函數(shù)。等號后面的onClick()是我們自己定義在LoginComponent中的函數(shù),這個(gè)名稱你可以隨便定成什么,不一定叫onClick()。下面我們就來定義這個(gè)函數(shù),在LoginComponent中寫一個(gè)叫onClick()的方法,內(nèi)容很簡單就是把“button was clicked”輸出到Console。
onClick() { console.log("button was clicked"); }
返回瀏覽器,并按F12調(diào)出開發(fā)者工具。當(dāng)你點(diǎn)擊Login時(shí),會發(fā)現(xiàn)Console窗口輸出了我們期待的文字。
那么如果要在onClick中傳遞一個(gè)參數(shù),比如是上面的文本輸入框輸入的值怎么處理呢?我們可以在文本輸入框標(biāo)簽內(nèi)加一個(gè)#usernameRef,這個(gè)叫引用(reference)。注意這個(gè)引用是的input對象,我們?nèi)绻雮鬟finput的值,可以用usernameRef.value,然后就可以把onClick()方法改成onClick(usernameRef.value)
在Component內(nèi)部的onClick方法也要隨之改寫成一個(gè)接受username的方法
onClick(username) { console.log(username); }
現(xiàn)在我們再看看結(jié)果是什么樣子,在文本輸入框中鍵入“hello”,點(diǎn)擊Login按鈕,觀察Console窗口:hello被輸出了。
好了,現(xiàn)在我們再加一個(gè)密碼輸入框,然后改寫onClick方法可以同時(shí)接收2個(gè)參數(shù):用戶名和密碼。代碼如下:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "app-login", template: ``, styles: [] }) export class LoginComponent implements OnInit { constructor() { } ngOnInit() { } onClick(username, password) { console.log("username:" + username + " " + "password:" + password); } }
看看結(jié)果吧,在瀏覽器中第一個(gè)輸入框輸入“wang”,第二個(gè)輸入框輸入“1234567”,觀察Console窗口,Bingo!
如果我們把登錄的業(yè)務(wù)邏輯在onClick方法中完成,當(dāng)然也可以,但是這樣做的耦合性太強(qiáng)了。設(shè)想一下,如果我們增加了微信登錄、微博登錄等,業(yè)務(wù)邏輯會越來越復(fù)雜,顯然我們需要把這個(gè)業(yè)務(wù)邏輯分離出去。那么我們接下來創(chuàng)建一個(gè)AuthService吧, 首先我們在srcapp下建立一個(gè)core的子文件夾(srcappcore),然后命令行中輸入 ng g s coreauth (s這里是service的縮寫,coreauth是說在core的目錄下建立auth服務(wù)相關(guān)文件)。auth.service.ts和auth.service.spec.ts這個(gè)兩個(gè)文件應(yīng)該已經(jīng)出現(xiàn)在你的目錄里了。
下面我們?yōu)檫@個(gè)service添加一個(gè)方法,你可能注意到這里我們?yōu)檫@個(gè)方法指定了返回類型和參數(shù)類型。這就是TypeScript帶來的好處,有了類型約束,你在別處調(diào)用這個(gè)方法時(shí),如果給出的參數(shù)類型或返回類型不正確,IDE就可以直接告訴你錯(cuò)了。
import { Injectable } from "@angular/core"; @Injectable() export class AuthService { constructor() { } loginWithCredentials(username: string, password: string): boolean { if(username === "wangpeng") return true; return false; } }
等一下,這個(gè)service雖然被創(chuàng)建了,但仍然無法在Component中使用。當(dāng)然你可以在Component中import這個(gè)服務(wù),然后實(shí)例化后使用,但是這樣做并不好,仍然時(shí)一個(gè)緊耦合的模式,Angular2提供了一種依賴性注入(Dependency Injection)的方法。
什么是依賴性注入?如果不使用DI(依賴性注入)的時(shí)候,我們自然的想法是這樣的,在login.component.ts中import引入AuthService,在構(gòu)造中初始化service,在onClick中調(diào)用service。
import { Component, OnInit } from "@angular/core"; //引入AuthService import { AuthService } from "../core/auth.service"; @Component({ selector: "app-login", template: ``, styles: [] }) export class LoginComponent implements OnInit { //聲明成員變量,其類型為AuthService service: AuthService; constructor() { this.service = new AuthService(); } ngOnInit() { } onClick(username, password) { //調(diào)用service的方法 console.log("auth result is: " + this.service.loginWithCredentials(username, password)); } }
這么做呢也可以跑起來,但存在幾個(gè)問題:
由于實(shí)例化是在組件中進(jìn)行的,意味著我們?nèi)绻膕ervice的構(gòu)造函數(shù)的話,組件也需要更改。
如果我們以后需要開發(fā)、測試和生產(chǎn)環(huán)境配置不同的AuthService,以這種方式實(shí)現(xiàn)會非常不方便。
下面我們看看如果使用DI是什么樣子的,首先我們需要在組件的修飾器中配置AuthService,然后在組件的構(gòu)造函數(shù)中使用參數(shù)進(jìn)行依賴注入。
import { Component, OnInit } from "@angular/core"; import { AuthService } from "../core/auth.service"; @Component({ selector: "app-login", template: ``, styles: [], //在providers中配置AuthService providers:[AuthService] }) export class LoginComponent implements OnInit { //在構(gòu)造函數(shù)中將AuthService示例注入到成員變量service中 //而且我們不需要顯式聲明成員變量service了 constructor(private service: AuthService) { } ngOnInit() { } onClick(username, password) { console.log("auth result is: " + this.service.loginWithCredentials(username, password)); } }
看到這里你會發(fā)現(xiàn)我們?nèi)匀恍枰猧mport相關(guān)的服務(wù),這是import是要將類型引入進(jìn)來,而provider里面會配置這個(gè)類型的實(shí)例。當(dāng)然即使這樣還是不太爽,可不可以不引入AuthService呢?答案是可以。
我們看一下app.module.ts,這個(gè)根模塊文件中我們發(fā)現(xiàn)也有個(gè)providers,根模塊中的這個(gè)providers是配置在模塊中全局可用的service或參數(shù)的。
providers: [ {provide: "auth", useClass: AuthService} ]
providers是一個(gè)數(shù)組,這個(gè)數(shù)組呢其實(shí)是把你想要注入到其他組件中的服務(wù)配置在這里。大家注意到我們這里的寫法和上面優(yōu)點(diǎn)區(qū)別,沒有直接寫成
providers:[AuthService]
而是給出了一個(gè)對象,里面有兩個(gè)屬性,provide和useClass,provide定義了這個(gè)服務(wù)的名稱,有需要注入這個(gè)服務(wù)的就引用這個(gè)名稱就好。useClass指明這個(gè)名稱對應(yīng)的服務(wù)是一個(gè)類,本例中就是AuthService了。這樣定義好之后,我們就可以在任意組件中注入這個(gè)依賴了。下面我們改動一下login.component.ts,去掉頭部的import { AuthService } from "../core/auth.service";和組件修飾器中的providers,更改其構(gòu)造函數(shù)為
onstructor(@Inject("auth") private service) { }
我們?nèi)サ袅藄ervice的類型聲明,但加了一個(gè)修飾符@Inject("auth"),這個(gè)修飾符的意思是請到系統(tǒng)配置中找到名稱為auth的那個(gè)依賴注入到我修飾的變量中。當(dāng)然這樣改完后你會發(fā)現(xiàn)Inject這個(gè)修飾符系統(tǒng)不識別,我們需要在@angular/core中引用這個(gè)修飾符,現(xiàn)在login.component.ts看起來應(yīng)該是下面這個(gè)樣子
import { Component, OnInit, Inject } from "@angular/core"; @Component({ selector: "app-login", template: `雙向數(shù)據(jù)綁定`, styles: [] }) export class LoginComponent implements OnInit { constructor(@Inject("auth") private service) { } ngOnInit() { } onClick(username, password) { console.log("auth result is: " + this.service.loginWithCredentials(username, password)); } }
接下來的問題是我們是否只能通過這種方式進(jìn)行表現(xiàn)層和邏輯之間的數(shù)據(jù)交換呢?如果我們希望在組件內(nèi)對數(shù)據(jù)進(jìn)行操作后再反饋到界面怎么處理呢?Angular2提供了一個(gè)雙向數(shù)據(jù)綁定的機(jī)制。這個(gè)機(jī)制是這樣的,在組件中提供成員數(shù)據(jù)變量,然后在模板中引用這個(gè)數(shù)據(jù)變量。我們來改造一下login.component.ts,首先在class中聲明2個(gè)數(shù)據(jù)變量username和password。
username = ""; password = "";
然后去掉onClick方法的參數(shù),并將內(nèi)部的語句改造成如下樣子:
console.log("auth result is: " + this.service.loginWithCredentials(this.username, this.password));
去掉參數(shù)的原因是雙向綁定后,我們通過數(shù)據(jù)成員變量就可以知道用戶名和密碼了,不需要在傳遞參數(shù)了。而成員變量的引用方式是this.成員變量。
然后我們來改造模板:
[(ngModel)]="username"這個(gè)看起來很別扭,稍微解釋一下,方括號[]的作用是說把等號后面當(dāng)成表達(dá)式來解析而不是當(dāng)成字符串,如果我們?nèi)サ舴嚼ㄌ柲蔷偷扔谡f是直接給這個(gè)ngModel賦值成“username”這個(gè)字符串了。方括號的含義是單向綁定,就是說我們在組件中給model賦的值會設(shè)置到HTML的input控件中。[()]是雙向綁定的意思,就是說HTML對應(yīng)控件的狀態(tài)的改變會反射設(shè)置到組件的model中。ngModel是FormModule中提供的指令,它負(fù)責(zé)從Domain Model(這里就是username或password,以后我們可用綁定更復(fù)雜的對象)中創(chuàng)建一個(gè)FormControl的實(shí)例,并將這個(gè)實(shí)例和表單的控件綁定起來。同樣的對于click事件的處理,我們不需要傳入?yún)?shù)了,因?yàn)槠湔{(diào)用的是剛剛我們改造的組件中的onClick方法?,F(xiàn)在我們保存文件后打開瀏覽器看一下,效果和上一節(jié)的應(yīng)該一樣的。本節(jié)的完整代碼如下:
//login.component.ts import { Component, OnInit, Inject } from "@angular/core"; @Component({ selector: "app-login", template: `表單數(shù)據(jù)的驗(yàn)證`, styles: [] }) export class LoginComponent implements OnInit { username = ""; password = ""; constructor(@Inject("auth") private service) { } ngOnInit() { } onClick() { console.log("auth result is: " + this.service.loginWithCredentials(this.username, this.password)); } }
通常情況下,表單的數(shù)據(jù)是有一定的規(guī)則的,我們需要依照其規(guī)則對輸入的數(shù)據(jù)做驗(yàn)證以及反饋驗(yàn)證結(jié)果。Angular2中對表單驗(yàn)證有非常完善的支持,我們繼續(xù)上面的例子,在login組件中,我們定義了一個(gè)用戶名和密碼的輸入框,現(xiàn)在我們來為它們加上規(guī)則。首先我們定義一下規(guī)則,用戶名和密碼都是必須輸入的,也就是不能為空。更改login.component.ts中的模板為下面的樣子
{{usernameRef.valid}} {{passwordRef.valid}}
注意到我們只是為username和password兩個(gè)控件加上了required這個(gè)屬性,表明這兩個(gè)控件為必填項(xiàng)。通過#usernameRef="ngModel"我們重新又加入了引用,這次的引用指向了ngModel,這個(gè)引用是要在模板中使用的,所以才加入這個(gè)引用如果不需要在模板中使用,可以不要這句。{{表達(dá)式}}雙花括號表示解析括號中的表達(dá)式,并把這個(gè)值輸出到模板中。這里我們?yōu)榱丝梢燥@性的看到控件的驗(yàn)證狀態(tài),直接在對應(yīng)控件后輸出了驗(yàn)證的狀態(tài)。初始狀態(tài)可以看到2個(gè)控件的驗(yàn)證狀態(tài)都是false,試著填寫一些字符在兩個(gè)輸入框中,看看狀態(tài)變化吧。
我們是知道了驗(yàn)證的狀態(tài)是什么,但是如果我們想知道驗(yàn)證失敗的原因怎么辦呢?我們只需要將{{usernameRef.valid}}替換成{{usernameRef.errors | json}}。|是管道操作符,用于將前面的結(jié)果通過管道輸出成另一種格式,這里就是把errors對象輸出成json格式的意思??匆幌陆Y(jié)果吧,返回的結(jié)果如下
如果除了不能為空,我們?yōu)閡sername再添加一個(gè)規(guī)則試試看呢,比如字符數(shù)不能少于3。
現(xiàn)在我們試著把{{表達(dá)式}}替換成友好的錯(cuò)誤提示,我們想在有錯(cuò)誤發(fā)生時(shí)顯示錯(cuò)誤的提示信息。那么我們來改造一下template。
{{ usernameRef.errors | json }}this is requiredshould be at least 3 charactorsthis is required
ngIf也是一個(gè)Angular2的指令,顧名思義,是用于做條件判斷的。*ngIf="usernameRef.errors?.required"的意思是當(dāng)usernameRef.errors.required為true時(shí)顯示div標(biāo)簽。那么那個(gè)?是干嘛的呢?因?yàn)?b>errors可能是個(gè)null,如果這個(gè)時(shí)候調(diào)用errors的required屬性肯定會引發(fā)異常,那么?就是標(biāo)明errors可能為空,在其為空時(shí)就不用調(diào)用后面的屬性了。
如果我們把用戶名和密碼整個(gè)看成一個(gè)表單的話,我們應(yīng)該把它們放在一對標(biāo)簽中,類似的加入一個(gè)表單的引用formRef。
這時(shí)運(yùn)行后會發(fā)現(xiàn)原本好用的代碼出錯(cuò)了,這是由于如果在一個(gè)大的表單中,ngModel會注冊成Form的一個(gè)子控件,注冊子控件需要一個(gè)name,這要求我們顯式的指定對應(yīng)控件的name,因此我們需要為input增加name屬性
既然我們增加了一個(gè)formRef,我們就看看formRef.value有什么吧。
首先為form增加一個(gè)表單提交事件的處理
。
然后在組件中增加一個(gè)onSubmit方法
onSubmit(formValue) { console.log(formValue); }
你會發(fā)現(xiàn)formRef.value中包括了表單所有填寫項(xiàng)的值。
有時(shí)候在表單項(xiàng)過多時(shí)我們需要對表單項(xiàng)進(jìn)行分組,HTML中提供了fieldset標(biāo)簽用來處理。那么我們看看怎么和Angular2結(jié)合吧:
意味著我們對于fieldset之內(nèi)的數(shù)據(jù)都分組到了login對象中。
接下來我們改寫onSubmit方法用來替代onClick,因?yàn)榭雌饋磉@兩個(gè)按鈕重復(fù)了,我們需要去掉onClick。首先去掉template中的,然后把標(biāo)簽后的Submit文本替換成Login,最后改寫onSubmit方法。
onSubmit(formValue) { console.log("auth result is: " + this.service.loginWithCredentials(formValue.login.username, formValue.login.password)); }
在瀏覽器中試驗(yàn)一下吧,所有功能正常工作。
驗(yàn)證結(jié)果的樣式自定義如果我們在開發(fā)工具中查看網(wǎng)頁源碼,可以看到
用戶名控件的HTML代碼是下面的樣子:在驗(yàn)證結(jié)果為false時(shí)input的樣式是ng-invalid
類似的可以實(shí)驗(yàn)一下,填入一些字符滿足驗(yàn)證要求之后,看input的HTML是下面的樣子:在驗(yàn)證結(jié)果為true時(shí)input的樣式是ng-valid
知道這個(gè)后,我們可以自定義不同驗(yàn)證狀態(tài)下的控件樣式。在組件的修飾符中把styles數(shù)組改寫一下:
styles: [` .ng-invalid{ border: 3px solid red; } .ng-valid{ border: 3px solid green; } `]
保存一下,返回瀏覽器可以看到,驗(yàn)證不通過時(shí)
驗(yàn)證通過時(shí)是這樣的:
最后說一下,我們看到這樣設(shè)置完樣式后連form和fieldset都一起設(shè)置了,這是由于form和fieldset也在樣式中應(yīng)用了.ng-valid和.ng-valid,那怎么解決呢?只需要在.ng-valid加上input即可,它表明的是應(yīng)用于input類型控件并且class引用了ng-invalid的元素。
styles: [` input.ng-invalid{ border: 3px solid red; } input.ng-valid{ border: 3px solid green; } `]
很多開發(fā)人員不太了解CSS,其實(shí)CSS還是比較簡單的,我建議先從Selector開始看,Selector的概念弄懂后Angular2的開發(fā)CSS就會順暢很多。具體可見W3School中對于CSS Selctor的參考和https://css-tricks.com/multip...。
本節(jié)代碼: https://github.com/wpcfan/awe...
進(jìn)一步的練習(xí)練習(xí)1:如果我們想給username和password輸入框設(shè)置默認(rèn)值。比如“請輸入用戶名”和“請輸入密碼”,自己動手試一下吧。
練習(xí)2:如果我們想在輸入框聚焦時(shí)把默認(rèn)文字清除掉,該怎么做?
練習(xí)3:如果我們想把默認(rèn)文字顏色設(shè)置成淺灰色該怎么做?
第一節(jié):Angular 2.0 從0到1 (一)
第二節(jié):Angular 2.0 從0到1 (二)
第三節(jié):Angular 2.0 從0到1 (三)
第四節(jié):Angular 2.0 從0到1 (四)
第五節(jié):Angular 2.0 從0到1 (五)
第六節(jié):Angular 2.0 從0到1 (六)
第七節(jié):Angular 2.0 從0到1 (七)
第八節(jié):Angular 2.0 從0到1 (八)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81340.html
摘要:官方支持微軟出品,是的超集,是的強(qiáng)類型版本作為首選編程語言,使得開發(fā)腳本語言的一些問題可以更早更方便的找到。第一個(gè)組件那么我們來為我們的增加一個(gè)吧,在命令行窗口輸入。引導(dǎo)過程通過在中引導(dǎo)來啟動應(yīng)用。它們的核心就是。 第一節(jié):Angular 2.0 從0到1 (一)第二節(jié):Angular 2.0 從0到1 (二)第三節(jié):Angular 2.0 從0到1 (三) 第一章:認(rèn)識Angular...
摘要:如果該構(gòu)造函數(shù)在我們所期望的中運(yùn)行,就沒有任何祖先注入器能夠提供的實(shí)例,于是注入器會放棄查找。但裝飾器表示找不到該服務(wù)也無所謂。用處理導(dǎo)航到子路由的情況。路由器會先按照從最深的子路由由下往上檢查的順序來檢查守護(hù)條件。 第一節(jié):Angular 2.0 從0到1 (一)第二節(jié):Angular 2.0 從0到1 (二)第三節(jié):Angular 2.0 從0到1 (三)第四節(jié):Angular 2...
摘要:如何在中使用動畫前端掘金本文講一下中動畫應(yīng)用的部分。與的快速入門指南推薦前端掘金是非常棒的框架,能夠創(chuàng)建功能強(qiáng)大,動態(tài)功能的。自發(fā)布以來,已經(jīng)廣泛應(yīng)用于開發(fā)中。 如何在 Angular 中使用動畫 - 前端 - 掘金本文講一下Angular中動畫應(yīng)用的部分。 首先,Angular本生不提供動畫機(jī)制,需要在項(xiàng)目中加入Angular插件模塊ngAnimate才能完成Angular的動畫機(jī)制...
摘要:而且此時(shí)我們注意到其實(shí)沒有任何一個(gè)地方目前還需引用了,這就是說我們可以安全地把從組件中的修飾符中刪除了。 第一節(jié):Angular 2.0 從0到1 (一)第二節(jié):Angular 2.0 從0到1 (二)第三節(jié):Angular 2.0 從0到1 (三) 作者:王芃 [email protected] 第四節(jié):進(jìn)化!模塊化你的應(yīng)用 一個(gè)復(fù)雜組件的分拆 上一節(jié)的末尾我偷懶的甩出了大量代碼,可能...
摘要:接下來繼續(xù)介紹三種架構(gòu)模式,分別是查詢分離模式微服務(wù)模式多級緩存模式。分布式應(yīng)用程序可以基于實(shí)現(xiàn)諸如數(shù)據(jù)發(fā)布訂閱負(fù)載均衡命名服務(wù)分布式協(xié)調(diào)通知集群管理選舉分布式鎖和分布式隊(duì)列等功能。 SpringCloud 分布式配置 SpringCloud 分布式配置 史上最簡單的 SpringCloud 教程 | 第九篇: 服務(wù)鏈路追蹤 (Spring Cloud Sleuth) 史上最簡單的 S...
閱讀 2676·2021-11-25 09:43
閱讀 2484·2021-09-22 15:29
閱讀 1000·2021-09-22 15:17
閱讀 3640·2021-09-03 10:36
閱讀 2236·2019-08-30 13:54
閱讀 1757·2019-08-30 11:23
閱讀 1171·2019-08-29 16:58
閱讀 1301·2019-08-29 16:14