本章節我們將為大家介紹如何將數據顯示到用戶界面上,可以使用以下三種方式:
通過插值表達式顯示組件的屬性
通過 NgFor 顯示數組型屬性
通過 NgIf 實現按條件顯示
通過插值表達式顯示組件的屬性
要顯示組件的屬性,插值是最簡單的方式,格式為:{{屬性名}}。
以下代碼基于 AngularJS2 TypeScript 環境配置 來創建,你可以再該章節上下載源碼,并修改以下提到的幾個文件。
app/app.component.ts 文件:
import{Component}from'@angular/core';@Component({selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜歡的網站: {{mySite}}</h2> `})exportclassAppComponent{title='站點列表'; mySite='菜鳥教程';}
Angular 會自動從組件中提取 title 和 mySite 屬性的值,并顯示在瀏覽器中,顯示信息如下:
注意:模板是包在反引號 (`) 中的一個多行字符串,而不是單引號 (')。
使用 ngFor 顯示數組屬性
我們也可以循環輸出多個站點,修改以下文件:
app/app.component.ts 文件:
import{Component}from'@angular/core';@Component({selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜歡的網站: {{mySite}}</h2> <p>網站列表:</p> <ul> <li *ngFor="let site of sites"> {{site}} </li> </ul> `})exportclassAppComponent{title='站點列表'; sites=['菜鳥教程', 'Google', 'Taobao', 'Facebook']; mySite=this.sites[0];}
代碼中我們在模板使用 Angular 的 ngFor 指令來顯示 sites 列表中的每一個條目,不要忘記 *ngFor 中的前導星號 (*) 。。
修改后,瀏覽器顯示如下所示:
實例中 ngFor 循環了一個數組, 事實上 ngFor 可以迭代任何可迭代的對象。
接下來我們在 app 目錄下創建 site.ts 的文件,代碼如下:
app/site.ts 文件:
exportclassSite{constructor(publicid: number, publicname: string){}}
以上代碼中定義了一個帶有構造函數和兩個屬性: id 和 name 的類。
接著我們循環輸出 Site 類的 name 屬性:
app/app.component.ts 文件:
import{Component}from'@angular/core';import{Site}from'./site'; @Component({selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜歡的網站: {{mySite.name}}</h2> <p>網站列表:</p> <ul> <li *ngFor="let site of sites"> {{site.name}} </li> </ul> `})exportclassAppComponent{title='站點列表'; sites=[newSite(1, '菜鳥教程'), newSite(2, 'Google'), newSite(3, 'Taobao'), newSite(4, 'Facebook')]; mySite=this.sites[0];}
修改后,瀏覽器顯示如下所示:
通過 NgIf 進行條件顯示
我們可以使用 NgIf 來設置輸出指定條件的數據。
以下實例中我們判斷如果網站數 3 個以上,輸出提示信息:修改以下 app.component.ts 文件,代碼如下:
app/app.component.ts 文件:
import{Component}from'@angular/core';import{Site}from'./site'; @Component({selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>我喜歡的網站: {{mySite.name}}</h2> <p>網站列表:</p> <ul> <li *ngFor="let site of sites"> {{site.name}} </li> </ul> <p *ngIf="sites.length > 3">你有很多個喜歡的網站!</p> `})exportclassAppComponent{title='站點列表'; sites=[newSite(1, '菜鳥教程'), newSite(2, 'Google'), newSite(3, 'Taobao'), newSite(4, 'Facebook')]; mySite=this.sites[0];}
修改后,瀏覽器顯示如下所示,底部多了個提示信息:
用戶點擊鏈接、按下按鈕或者輸入文字時,這些用戶的交互行為都會觸發 DOM 事件。
本章中,我們將學習如何使用 Angular 事件綁定語法來綁定這些事件。
以下Gif圖演示了該實例的操作:
源代碼可以再文章末尾下載。
綁定到用戶輸入事件
我們可以使用 Angular 事件綁定機制來響應任何 DOM 事件 。
以下實例將綁定了點擊事件:
<button (click)="onClickMe()">點我!</button>
等號左邊的 (click) 表示把該按鈕的點擊事件作為綁定目標 。 等號右邊,引號中的文本是一個 模板語句
完整代碼如下:
app/click-me.component.ts 文件:
import{Component}from'@angular/core'; @Component({selector: 'click-me', template: ` <button(click)="onClickMe()">點我!</button> {{clickMessage}}`})exportclassClickMeComponent{clickMessage=''; onClickMe(){this.clickMessage='菜鳥教程!'; }}
通過 $event 對象取得用戶輸入
我們可以綁定到所有類型的事件。
讓我們試試綁定到一個輸入框的 keyup 事件,并且把用戶輸入的東西回顯到屏幕上。
app/keyup.component.ts (v1) 文件:
@Component({selector: 'key-up1', template: ` <input(keyup)="onKey($event)"> <p>{{values}}</p> `})exportclassKeyUpComponent_v1{values=''; /* // 非強類型 onKey(event:any) { this.values +=event.target.value + ' | '; } */// 強類型onKey(event: KeyboardEvent){this.values +=(<HTMLInputElement>event.target).value + ' | '; }}
以上代碼中我們監聽了一個事件并捕獲用戶輸入,Angular 把事件對象存入 $event 變量中。
組件的 onKey() 方法是用來從事件對象中提取出用戶輸入的,再將輸入的值累加到 values 的屬性。
從一個模板引用變量中獲得用戶輸入
你可以通過使用局部模板變量來顯示用戶數據,模板引用變量通過在標識符前加上井號 (#) 來實現。
下面的實例演示如何使用局部模板變量:
app/loop-back.component.ts 文件:
@Component({selector: 'loop-back', template: ` <input #box(keyup)="0"> <p>{{box.value}}</p> `})exportclassLoopbackComponent{}
我們在
<input>
元素上定義了一個名叫box
的模板引用變量。box
變量引用的就是<input>
元素本身,這意味著我們可以獲得 input 元素的value
值,并通過插值表達式把它顯示在<p>
標簽中。我們可以使用模板引用變量來修改以上 keyup 的實例:
app/keyup.components.ts (v2) 文件:
@Component({selector: 'key-up2', template: ` <input #box(keyup)="onKey(box.value)"> <p>{{values}}</p> `})exportclassKeyUpComponent_v2{values=''; onKey(value: string){this.values +=value + ' | '; }}
按鍵事件過濾 ( 通過 key.enter)
我們可以只在用戶按下回車 (enter) 鍵的時候才獲取輸入框的值。
(keyup) 事件處理語句會聽到每一次按鍵,我們可以過濾按鍵,比如每一個 $event.keyCode,只有在按下回車鍵才更新 values 屬性。
Angular 可以為我們過濾鍵盤事件,通過綁定到 Angular 的 keyup.enter 偽事件監聽回車鍵的事件。
app/keyup.components.ts (v3):
@Component({selector: 'key-up3', template: ` <input #box(keyup.enter)="values=box.value"> <p>{{values}}</p> `})exportclassKeyUpComponent_v3{values='';}
blur( 失去焦點 ) 事件
接下來我們可以使用blur( 失去焦點 ) 事件,它可以再元素失去焦點后更新 values 屬性。
以下實例同時監聽輸入回車鍵與輸入框失去焦點的事件。
app/keyup.components.ts (v4):
@Component({selector: 'key-up4', template: ` <input #box(keyup.enter)="values=box.value"(blur)="values=box.value"> <p>{{values}}</p> `})exportclassKeyUpComponent_v4{values='';}
本章節我們將為大家介紹如何使用組件和模板構建一個 Angular 表單。
利用 Angular 模板,我們可以創建各種類型表單,例如:登錄表單,聯系人表單,商品詳情表單等,而且我們也為這些表單的字段添加數據校驗。
接下來我們一步步來實現表單的功能。
創建項目
導入初始化項目。
完整的項目創建可以參考:AngularJS2 TypeScript 環境配置
創建 Site 模型
以下創建了一個簡單的模型類 Site,包含了三個必需字段:id,name,url,一個可選字段:alexa。
在 angular-forms/app 目錄下創建 site.ts 文件,代碼如下:
app/site.ts 文件:
exportclassSite{constructor(publicid: number, publicname: string, publicurl: string, publicalexa?: number){}}
以下代碼中,標為 public 的為公有字段,alexa 后添加一個問號(?)表示可選字段。
創建一個表單組件
每個 Angular 表單分為兩部分:一個基于 HTML 的模板,和一個基于代碼的組件,它用來處理數據和用戶交互。
在 angular-forms/app 目錄下創建 site-form.component.ts 文件,代碼如下:
app/site-form.component.ts 文件:
import{Component}from'@angular/core';import{Site}from'./site'; @Component({moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html'})exportclassSiteFormComponent{urls=['www.runoob.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model=newSite(1, '菜鳥教程', this.urls[0], 10000); submitted=false; onSubmit(){this.submitted=true; }// TODO: 完成后移除getdiagnostic(){returnJSON.stringify(this.model); }}
實例中導入了 Component 裝飾器和 Site 模型。
@Component 選擇器 "site-form" 表示我們可以通過一個 <site-form> 標簽,把此表單扔進父模板中。
templateUrl 屬性指向一個獨立的HTML模板文件,名叫 site-form.component.html。
diagnostic 屬性用于返回這個模型的JSON形式。
定義應用的根模塊
修改 app.module.ts 來定義應用的根模塊,模塊可中指定了引用到的外部及聲明屬于本模塊中的組件,比如 SiteFormComponent。
因為模板驅動的表單有它們自己的模塊,所以我們得把 FormsModule 添加到本應用的 imports 數組中,這樣我們才能使用表單。
app/app.module.ts 文件代碼如下
app/app.module.ts 文件:
import{NgModule}from'@angular/core';import{BrowserModule}from'@angular/platform-browser';import{FormsModule}from'@angular/forms';import{AppComponent}from'./app.component';import{SiteFormComponent}from'./site-form.component'; @NgModule({imports: [BrowserModule, FormsModule], declarations: [AppComponent, SiteFormComponent], bootstrap: [AppComponent]})exportclassAppModule{}
創建根組件
修改根組件文件 app.component.ts,將 SiteFormComponent 將被放在其中。
app/app.component.ts 文件:
import{Component}from'@angular/core'; @Component({selector: 'my-app', template: '<site-form></site-form>'})exportclassAppComponent{}
創建一個初始 HTML 表單模板
創建模板文件 site-form.component.html ,代碼如下所示:
app/site-form.component.html 文件:
<divclass="container"><h1>網站表單</h1><form><divclass="form-group"><labelfor="name">網站名</label><inputtype="text"class="form-control"id="name"required></div><divclass="form-group"><labelfor="alterEgo">alexa 排名</label><inputtype="text"class="form-control"id="alexa"></div><buttontype="submit"class="btn btn-default">提交</button></form></div>
required 屬性設置的該字段為必需字段,如果沒有設置則是可選。
在 angular-forms 目錄下輸入以下命令:
cnpm install bootstrap --save
打開 index.html 文件,把以下樣式鏈接添加到 <head> 中:
<linkrel="stylesheet"href="node_modules/bootstrap/dist/css/bootstrap.min.css">
執行 npm start 后,訪問:http://localhost:3000/,輸出效果如下:
使用 ngModel 進行雙向數據綁定
接下來我們使用 ngModel 進行雙向數據綁定,通過監聽 DOM 事件,來實現更新組件的屬性。
修改 app/site-form.component.html ,使用 ngModel 把我們的表單綁定到模型。代碼如下所示:
app/site-form.component.html 文件:
<divclass="container"><h1>網站表單</h1><form> {{diagnostic}} <divclass="form-group"><labelfor="name">網站名</label><inputtype="text"class="form-control"id="name"required [(ngModel)]="model.name"name="name"></div><divclass="form-group"><labelfor="alexa">alexa 排名</label><inputtype="text"class="form-control"id="alexa" [(ngModel)]="model.alexa"name="alexa"></div><divclass="form-group"><labelfor="url">網站 URL </label><selectclass="form-control"id="url"required [(ngModel)]="model.url"name="url"><option *ngFor="let p of urls" [value]="p">{{p}}</option></select></div><buttontype="submit"class="btn btn-default">提交</button></form></div>
每一個 input 元素都有一個 id 屬性,它被 label 元素的 for 屬性用來把標簽匹配到對應的 input 。
每一個 input 元素都有一個 name 屬性, Angular 的表單模塊需要使用它為表單注冊控制器。
運行以上實例輸出結果如下:
{{diagnostic}} 只是用于測試時候輸出數據使用。
我們還可以通過 ngModel 跟蹤修改狀態與有效性驗證,它使用了三個 CSS 類來更新控件,以便反映當前狀態。
狀態 | 為 true 時的類 | 為 false 時的類 |
---|---|---|
控件已經被訪問過 | ng-touched | ng-untouched |
控件值已經變化 | ng-dirty | ng-pristine |
控件值是有效的 | ng-valid | ng-invalid |
這樣我們就可以添加自定義 CSS 來反應表單的狀態。
在 angular-forms 目錄下創建 forms.css 文件,代碼如下:
forms.css 文件:
.ng-valid[required], .ng-valid.required{border-left:5pxsolid#42A948; /* green */}.ng-invalid:not(form) {border-left:5pxsolid#a94442; /* red */}
打開 index.html 文件,把以下樣式鏈接添加到 <head> 中:
<linkrel="stylesheet"href="forms.css">
修改 app/site-form.component.html ,代碼如下所示:
app/site-form.component.html 文件:
<divclass="container"><h1>網站表單</h1><form> {{diagnostic}} <divclass="form-group"><labelfor="name">網站名</label><inputtype="text"class="form-control"id="name"required [(ngModel)]="model.name"name="name" #name="ngModel"><div [hidden]="name.valid || name.pristine"class="alert alert-danger"> 網站名是必需的 </div></div><divclass="form-group"><labelfor="alexa">alexa 排名</label><inputtype="text"class="form-control"id="alexa" [(ngModel)]="model.alexa"name="alexa"></div><divclass="form-group"><labelfor="url">網站 URL </label><selectclass="form-control"id="url"required [(ngModel)]="model.url"name="url"><option *ngFor="let p of urls" [value]="p">{{p}}</option></select></div><buttontype="submit"class="btn btn-default">提交</button></form></div>
模板中通過把 div 元素的 hidden 屬性綁定到 name 控件的屬性,我們就可以控制"name"字段錯誤信息的可見性了。
刪除掉 name 字段的數據,顯示結果如下所示:
添加一個網站
接下來我們創建一個用于添加網站的表單,在 app/site-form.component.html 添加一個按鈕:
app/site-form.component.html 文件:
<buttontype="button"class="btn btn-default" (click)="newSite()">添加網站</button>
將以上按鈕事件綁定到組件方法上:
app/site-form.component.ts 文件:
active=true; newSite(){this.model=newSite(5, '', ''); this.active=false; setTimeout(()=> this.active=true, 0);}
我們給組件添加一個 active 標記,把它初始化為 true 。當我們添加一個新的網站時,它把 active 標記設置為 false , 然后通過一個快速的 setTimeout 函數迅速把它設置回 true 。
通過 ngSubmit 來提交表單
我們可以使用 Angular 的指令 NgSubmit 來提交表單, 并且通過事件綁定機制把它綁定到 SiteFormComponent.submit() 方法上。
<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">
我們定義了一個模板引用變量 #siteForm ,并且把它初始化為 "ngForm" 。
這個 siteForm 變量現在引用的是 NgForm 指令,它代表的是表單的整體。
site-form.component.ts 文件完整代碼如下:
app/site-form.component.ts 文件:
import{Component}from'@angular/core';import{Site}from'./site'; @Component({moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html'})exportclassSiteFormComponent{urls=['www.runoob.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model=newSite(1, '菜鳥教程', this.urls[0], 10000); submitted=false; onSubmit(){this.submitted=true; }// TODO: 完成后移除getdiagnostic(){returnJSON.stringify(this.model); }active=true; newSite(){this.model=newSite(5, '', ''); this.active=false; setTimeout(()=> this.active=true, 0); }}
app/site-form.component.html 完整代碼如下:
app/site-form.component.html 文件:
<divclass="container"><div [hidden]="submitted"><h1>網站表單</h1><form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm"> {{diagnostic}} <divclass="form-group"><labelfor="name">網站名</label><inputtype="text"class="form-control"id="name"required [(ngModel)]="model.name"name="name" #name="ngModel"><div [hidden]="name.valid || name.pristine"class="alert alert-danger"> 網站名是必需的 </div></div><divclass="form-group"><labelfor="alexa">alexa 排名</label><inputtype="text"class="form-control"id="alexa" [(ngModel)]="model.alexa"name="alexa"></div><divclass="form-group"><labelfor="url">網站 URL </label><selectclass="form-control"id="url"required [(ngModel)]="model.url"name="url"><option *ngFor="let p of urls" [value]="p">{{p}}</option></select></div><buttontype="submit"class="btn btn-default" [disabled]="!siteForm.form.valid">提交</button><buttontype="button"class="btn btn-default" (click)="newSite()">新增網站</button></form></div><div [hidden]="!submitted"><h2>你提交的信息如下:</h2><divclass="row"><divclass="col-xs-3">網站名</div><divclass="col-xs-9 pull-left">{{ model.name }}</div></div><divclass="row"><divclass="col-xs-3">網站 alexa 排名</div><divclass="col-xs-9 pull-left">{{ model.alexa }}</div></div><divclass="row"><divclass="col-xs-3">網站 URL </div><divclass="col-xs-9 pull-left">{{ model.url }}</div></div><br><buttonclass="btn btn-default" (click)="submitted=false">編輯</button></div></div>
模板中我們把 hidden 屬性綁定到 SiteFormComponent.submitted 屬性上。
主表單從一開始就是可見的,因為 submitted 屬性是 false ,當我們提交了這個表單則隱藏,submitted 屬性是 true:
submitted=false; onSubmit(){this.submitted=true; }
最終的目錄結構為:
前面幾個章節我們已經接觸了 Angular 的模板,本文我們將具體介紹 Angular 的語法使用。
模板扮演的是一個視圖的角色,簡單講就是展示給用戶看的部分。
HTML
插值表達式
模板表達式
模板語句
綁定語法
屬性綁定
HTML 屬性、 class 和 style 綁定
事件綁定
使用 NgModel 進行雙向數據綁定
內置指令
* 與 <template>
模板引用變量
輸入輸出屬性
模板表達式操作符
HTML
HTML 是 Angular 模板的"語言",除了 <script> 元素是被禁用的外 ,其他 HTML 元素都是支持的,例如:
<h1>我的第一個 Angular 應用</h1>
插值表達式
插值表達式的語法格式為:{{ ... }}。
插值表達式可以把計算的字符串插入HTML中,也可以作為屬性值來使用。
<h3> {{title}} <imgsrc="{{imageUrl}}"style="height:30px"></h3>
模板表達式
{{ ... }} 里頭其實就是一個模板表達式,Angular 會對其進行求值并轉化為字符串輸出。
以下實例是兩個數相加:
<!-- "The sum of 1 + 1 is 2" --><p>The sum of 1 + 1 is {{1 + 1}}</p>
我們可以使用 getVal() 來獲取這個表達式的值:
<divclass="example"><divclass="example_code">[mycode3 type="html"]<!-- "4" --><p>{{1 + 1 + getVal()}}</p>
模板表達式類似 JavaScript 的語言,很多 JavaScript 表達式也是合法的模板表達式,但不是全部。
以下 JavaScript 表達式是禁止的:
賦值表達式(
=
,+=
,-=
...)new操作符
帶有
;
或者'
的連接表達式自增和自減操作(
++
和--
) 其他與Javascript語法不同的值得注意的包括:不支持位運算符(
|
和&
)模板表達式的操作符,如
|
和?.
等,被賦予了新的含義屬性綁定
模板的屬性綁定可以把視圖元素的屬性設置為模板表達式 。
最常用的屬性綁定是把元素的屬性設置為組件中屬性的值。 下面這個例子中, image 元素的 src 屬性會被綁定到組件的 imageUrl 屬性上:
<img [src]="imageUrl">
當組件為 isUnchanged( 未改變 ) 時禁用一個按鈕:
<button [disabled]="isUnchanged">按鈕是禁用的</button>
設置指令的屬性:
<div [ngClass]="classes">[ngClass]綁定到classes 屬性</div>
設置一個自定義組件的屬性(這是父子組件間通訊的重要途徑):
<user-detail [user]="currentUser"></user-detail>
HTML 屬性(Attribute)、 class 和 style 綁定
模板語法為那些不太適合使用屬性綁定的場景提供了專門的單向數據綁定形式。
屬性(Attribute)、綁定
當元素沒有屬性可綁的時候,使用HTML標簽屬性(Attribute)綁定。
考慮 ARIA, SVG 和 table 中的 colspan/rowspan 等屬性(Attribute) 。它們是純粹的屬性 。 它們沒有對應的屬性可供綁定。
以下實例會報錯:
<tr><tdcolspan="{{1 + 1}}">Three-Four</td></tr>
我們會得到這個錯誤:
Template parse errors:Can't bind to 'colspan' since it isn't a known native property模板解析錯誤:不能綁定到'colspan',因為它不是已知的原生屬性
正如提示中所說,
<td>
元素沒有colspan
屬性。 但是插值表達式和屬性綁定只能設置 屬性 ,而不是 Attribute,所以需HTML標簽 Attribute 綁定來創建和綁定類似的Attribute。HTML標簽特性綁定在語法上類似于屬性綁定,但中括號中的部分不是一個元素的屬性名,而是由一個attr.的前綴和HTML標簽屬性的名稱組成,然后通過一個能求值為字符串的表達式來設置HTML標簽屬性的值。如:
<tableborder=1><tr><td [attr.colspan]="1 + 1">One-Two</td></tr><tr><td>Five</td><td>Six</td></tr></table>
css類綁定
借助 CSS 類綁定 ,我們可以從元素的 class 屬性上添加和移除 CSS 類名。
CSS 類綁定在語法上類似于屬性綁定。但方括號中的部分不是一個元素的屬性名,而是包括一個 class 前綴,緊跟著一個點 (.) ,再跟著 CSS 類的名字組成。 其中后兩部分是可選的。例如: [class.class-name] 。
下面的例子展示了如何通過css類綁定類添加和移除"special"類:
<!-- 標準HTML樣式類設置 --><divclass="bad curly special">Bad curly special</div><!-- 通過綁定重設或覆蓋樣式類 --><divclass="bad curly special" [class]="badCurly">Bad curly</div><!-- 通過一個屬性值來添加或移除special樣式類 --><div [class.special]="isSpecial">這個樣式比較特殊</div>
style樣式綁定
通過樣式綁定,可以設置內聯樣式。樣式綁定語法上類似于屬性綁定,但中括號里面的部分不是一個元素的屬性名,樣式綁定包括一個style.,緊跟著css樣式的屬性名,例如:[style.style-property]。
<button [style.color]="isSpecial ? 'red': 'green'">紅色</button><button [style.background-color]="canSave ? 'cyan': 'grey'">保存</button><!-- 帶有單位的樣式綁定 --><button [style.font-size.em]="isSpecial ? 3 : 1">大</button><button [style.font-size.%]="!isSpecial ? 150 : 50">小</button>
樣式屬性可以是中線命名法(font-size),也可以是駝峰是命名法(fontSize)。
事件綁定
在事件綁定中,Angular通過監聽用戶動作,比如鍵盤事件、鼠標事件、觸屏事件等來響應相對應的數據流向-從視圖目標到數據源。
事件綁定的語法是由等號左側小括號內的 目標事件 和右側引號中的 模板聲明 組成。
比如下面這個例子,是事件綁定監聽按鈕的點擊事件。只要點擊鼠標,都會調用組件的 onSave()方法。
<button (click)="onSave()">保存</button>
圓括號中的名稱 ——比如 (click) ——標記出了目標事件。在下面這個例子中,目標是按鈕的 click 事件。
<button (click)="onSave()">Save</button>
也可以使用on- 前綴的形式:
<buttonon-click="onSave()">On Save</button>
使用 NgModel 進行雙向數據綁定
當開發數據輸入表單時,期望的結果是既能將組件的數據顯示到表單上,也能在用戶修改時更新組件的數據。
以下是一個通過 [(NgModel)] 來實現雙向綁定:
<input [(ngModel)]="currentUser.firstName">
[]實現了數據流從組件到模板,()實現了數據流從模板到組件,兩者一結合[()]就實現了雙向綁定。
使用前綴形式的語法:
<inputbindon-ngModel="currentUser.firstName">
內置指令
Angular 的內置指令有 NgClass、NgStyle、NgIf、NgFor、NgSwitch等。
NgClass
通過綁定到 NgClass 動態添加或刪除 CSS 類。
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'"> 這個div是大號的。</div>
NgStyle
NgStyle 通過把它綁定到一個key:value控制對象的形式,可以讓我們同時設置很多內聯樣式。
setStyles() { let styles={ // CSS屬性名 'font-style': this.canSave ? 'italic' : 'normal', // italic 'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal 'font-size': this.isSpecial ? '24px' : '8px', // 24px }; return styles;}
通過添加一個NgStyle屬性綁定,讓它調用setStyles,并據此來設置元素的樣式:
<div [ngStyle]="setStyles()"> 這個div的樣式是italic, normal weight, 和extra large (24px)。</div>
NgIf
通過把NgIf指令綁定到一個真值表達式,可以把一個元素及其子元素添加到DOM樹上。
<div *ngIf="currentUser">Hello,{{currentUser.firstName}}</div>
相反,綁定到一個假值表達式將從DOM樹中移除該元素及其子元素。如:
<!-- 因為isActive的值為false,所以User Detail不在DOM樹種--><user-detail *ngIf="isActive"></user-detail>
NgSwitch
當需要從一組可能的元素樹中根據條件顯示其中一個時,就需要NgSwitch了。Angular將只把選中的元素添加進DOM中。如:
<span [ngSwitch]="userName"><span *ngSwitchCase="'張三'">張三</span><span *ngSwitchCase="'李四'">李四</span><span *ngSwitchCase="'王五'">王五</span><span *ngSwitchCase="'趙六'">趙六</span><span *ngSwitchDefault>龍大</span></span>
把作為父指令的
NgSwitch
綁定到一個能返回開關值的表達式,例子中這個值是字符串,但它可以是任何類型的值。父指令NgSwitch
控制一組<span>
子元素。每個<span>
或者掛在一個匹配值的表達式上,或者被標記為默認情況。任何時候,這些span中最多只有一個會出現在DOM中。如果這個span的匹配值和開關值相等,Angular2就把這個<span>
添加DOM中。如果沒有任何span匹配上,Angular2就會把默認的span添加到DOM中。Angular2會移除并銷毀所有其他的span。三個相互合作的指令:
ngSwitch:綁定到一個返回開關值的表達式
ngSwitchCase:綁定到一個返回匹配值的表達式
ngSwitchDefault:一個用于標記默認元素的屬性 注意:不要再ngSwitch前使用
*
,而應該用屬性綁定,但ngSwitchCase和ngSwitchDefault前面要放*
。NgFor
當需要展示一個由多個條目組成的列表時就需要這個指令了。如下面這個例子,就是在一個HTML塊上應用NgFor。
<div *ngFor="let user of users">{{user.fullName}}</div>
NgFor也可以應用在一個組件元素上,如:
<user-detail *ngFor="let user of users" [user]="user"></user-detail>
ngFor指令支持一個可選的index索引,在迭代過程中會從0增長到數組中的長度。
可以通過模板輸入變量來捕獲這個index,并應用在模板中。下面的例子就把index捕獲到了一個名為i的變量中。
<div *ngFor="let user of users; let i=index">{{i + 1}} - {{user.fullName}}</div>
NgForTrackBy
ngFor 指令有時候會性能較差,特別是在大型列表中。 對一個條目的一點小更改、移除或添加,都會導致級聯的 DOM 操作。
比如,當通過重新從服務器來刷新通訊錄,刷新后的列表可能包含很多(如果不是全部的話)以前顯示過的聯系人。但在Angular看來,它不知道哪些是以前就存在過的,只能清理舊列表、舍棄那些DOM元素,并用新的DOM元素來重建一個新列表。
解決這個問題,可以通過追蹤函數來避免這種折騰。追蹤函數會告訴Angular:我們知道兩個具有相同user.id的對象是同一個聯系人。如:
trackByUsers(index: number, user: User){return user.id}
然后,把NgForTrackBy指令設置為那個追蹤函數:
<div *ngFor="let user of users; trackBy:trackByUsers">({{user.id}}) {{user.fullName}}</div>
追蹤函數不會排除所有DOM更改。如果用來判斷是否為同一個聯系人的屬性變化了,就會更新DOM元素,反之就會留下這個DOM元素。列表界面就會變得比較更加平滑,具有更好的響應效果。
模板引用變量
模板引用變量是模板中對 DOM 元素或指令的引用。
它能在原生 DOM 元素中使用,也能用于 Angular 組件——實際上,它可以和任何自定義 Web 組件協同工作。
我們可以在同一元素、兄弟元素或任何子元素中引用模板引用變量。
這里是關于創建和使用模板引用變量的兩個例子:
<!-- phone 引用了 input 元素,并將 `value` 傳遞給事件句柄 --><input #phoneplaceholder="phone number"><button (click)="callPhone(phone.value)">Call</button><!-- fax 引用了 input 元素,并將 `value` 傳遞給事件句柄 --><inputref-faxplaceholder="fax number"><button (click)="callFax(fax.value)">Fax</button>
"phone" 的 (#) 前綴意味著我們將要定義一個 phone 變量。
相關文章
https://gf-rd.gitbooks.io/angular-2-step-by-step/content/chapters/2.3.html
定義好的組件需要注冊才能被使用。 注冊方式有兩種
.component() 方法,讓組件在當前 Vue 應用中全局可用。 在 main.ts 中
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import GlobalTitle from '@/components/GlobalTitle.vue'
import App from './App.vue'
import router from './router'
const app=createApp(App)
app.component('GlobalTitle', GlobalTitle)
app.use(createPinia())
app.use(router)
app.mount('#app')
在 vue 中直接使用無需導入
<script lang="ts" setup>
import { ref } from 'vue'
</script>
<template>
<div class="container">
<GlobalTitle></GlobalTitle>
</div>
</template>
<style lang="scss" scoped>
.container {
}
</style>
效果:
全局注冊的組件可以在此應用的任意組件的模板中使用,所有的子組件也可以使用全局注冊的組件。
全局組件缺點
局部注冊的組件需要在使用它的父組件中顯式導入,并且只能在該父組件中使用。
它的優點是使組件之間的依賴關系更加明確,并且對 tree-shaking 更加友好。
定義組件
<script lang="ts" setup>
import { ref } from 'vue'
</script>
<template>
<div class="container">
<h2>這是一個局部組件</h2>
</div>
</template>
<style lang="scss" scoped>
.container {
}
</style>
局部使用組件
<script lang="ts" setup>
import { ref } from 'vue'
import PartTitle from '@/components/PartTitle.vue'
</script>
<template>
<div class="container">
<PartTitle />
</div>
</template>
<style lang="scss" scoped>
.container {
}
</style>
推薦 PascalCase 作為組件名的注冊格式。
在單文件組件和內聯字符串模板中,我們都推薦這樣做。
為了方便,Vue 支持將模板中使用 kebab-case 的標簽解析為使用 PascalCase 注冊的組件。
這意味著一個以 MyComponent 為名注冊的組件,在模板中可以通過 <MyComponent> 或 <my-component> 引用。這讓我們能夠使用同樣的 JavaScript 組件注冊代碼來配合不同來源的模板。
一個組件需要顯式聲明它所接受的 props,這樣 Vue 才能知道外部傳入的哪些是 props,哪些是透傳 attribute。
setup 寫法
組件定義
<script lang="ts" setup>
import { ref } from 'vue'
const props=defineProps(['person'])
</script>
<template>
<div class="container">
<h1>{{ props.person }}</h1>
</div>
</template>
<style lang="scss" scoped>
.container {
}
</style>
組件使用
<script lang="ts" setup>
import { ref } from 'vue'
import Com14 from '@/components/Com14.vue'
</script>
<template>
<div class="container">
<Com14 person="'王大可'" />
</div>
</template>
<style lang="scss" scoped>
.container {
}
</style>
聲明對象形式的屬性 setup JavaScript 形式
defineProps({
title: String,
likes: Number
})
setup TypeScript 形式
<script setup lang="ts">
defineProps<{
title?: string
likes?: number
}>()
</script>
對象形式的 props 聲明不僅可以一定程度上作為組件的文檔,而且如果其他開發者在使用你的組件時傳遞了錯誤的類型,也會在瀏覽器控制臺中拋出警告。
如果一個 prop 的名字很長,應使用 camelCase 形式,因為它們是合法的 JavaScript 標識符
defineProps({
greetingMessage: String
})
<span>{{ greetingMessage }}</span>
//推薦寫法
<MyComponent greeting-message="hello" />
//或者
<MyComponent greetingMessage="hello" />
模版上使用屬性則通常會將其寫為 kebab-case 形式,這樣和 HTML attribute 寫法就一致了。
簡單講 就是傳入數值是字符串還是變量
//這是靜態
<Com14 person="王大可" />
//這是動態
<Com14 :person="personName" />
v-bind 直接綁定對象,即只使用 v-bind 而非某一個屬性
const post={
id: 1,
title: 'My Journey with Vue'
}
<BlogPost v-bind="post" />
// 實際等價于
<BlogPost :id="post.id" :title="post.title" />
const props=defineProps(['foo'])
// ? 警告!prop 是只讀的!
props.foo='bar'
「更改 props 的場景:」
prop 被用于傳入初始值;而子組件想在之后將其作為一個局部數據屬性。
在這種情況下,最好是新定義一個局部數據屬性,從 props 上獲取初始值即可
const props=defineProps(['initialCounter'])
// 計數器只是將 props.initialCounter 作為初始值
// 像下面這樣做就使 prop 和后續更新無關了
const counter=ref(props.initialCounter)
需要對傳入的 prop 值做進一步的轉換。
在這種情況中,最好是基于該 prop 值定義一個計算屬性:
const props=defineProps(['size'])
// 該 prop 變更時計算屬性也會自動更新
const normalizedSize=computed(()=> props.size.trim().toLowerCase())
defineProps({
// 基礎類型檢查
// (給出 `null` 和 `undefined` 值則會跳過任何類型檢查)
propA: Number,
// 多種可能的類型
propB: [String, Number],
// 必傳,且為 String 類型
propC: {
type: String,
required: true
},
// Number 類型的默認值
propD: {
type: Number,
default: 100
},
// 對象類型的默認值
propE: {
type: Object,
// 對象或數組的默認值
// 必須從一個工廠函數返回。
// 該函數接收組件所接收到的原始 prop 作為參數。
default(rawProps) {
return { message: 'hello' }
}
},
// 自定義類型校驗函數
// 在 3.4+ 中完整的 props 作為第二個參數傳入
propF: {
validator(value, props) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
},
// 函數類型的默認值
propG: {
type: Function,
// 不像對象或數組的默認,這不是一個
// 工廠函數。這會是一個用來作為默認值的函數
default() {
return 'Default function'
}
}
})
defineProps() 宏中的參數不可以訪問 <script setup> 中定義的其他變量,因為在編譯時整個表達式都會被移到外部的函數中。
額外說明:
當 prop 的校驗失敗后,Vue 會拋出一個控制臺警告 (在開發模式下)。
運行時類型檢查
校驗選項中的 type 可以是下列這些原生構造函數:
type 也可以是自定義的類或構造函數,Vue 將會通過 instanceof 來檢查類型是否匹配。
class Person {
constructor(firstName, lastName) {
this.firstName=firstName
this.lastName=lastName
}
}
defineProps({
author: Person
})
Vue 會通過 instanceof Person 來校驗 author prop 的值是否是 Person 類的一個實例。
defineProps({
disabled: Boolean
})
<!-- 等同于傳入 :disabled="true" -->
<MyComponent disabled />
<!-- 等同于傳入 :disabled="false" -->
<MyComponent />
只有當 Boolean 出現在 String 之前時,Boolean 轉換規則才適用
一節講到對于元素的操作和瀏覽器的常用操作如何通過代碼實現,這次來學習如何通過定位元素,來獲取元素的信息(元素屬性、信息等)
獲取元素相關的信息
size:元素的大小
text:元素內文本
is_displayed( ) :元素是否可見
is_enabled(): 元素是否可用(一般用于判斷按鈕是否置灰)
is_selected( ) : 元素是否被選中(一般用于表單中的單選框和復選框)
get_attribute ( ) : 元素的屬性(可以獲取到所選標簽內的屬性信息)
通過如圖所示選中的元素來演示如何獲取元素的屬性
from selenium import webdriver
driver=webdriver.Chrome()
driver.get("http://news.baidu.com/")
# 新聞標題
element1=driver.find_element_by_css_selector("label[class='not-checked']")
# 新聞標題選擇框
element2=driver.find_element_by_css_selector("#newstitle")
# 新聞標題的大?。▄'height', 'width'})
print(element1.size)
# 新聞標題的文本
print(element1.text)
# 新聞標題是否可見
print(element1.is_displayed())
# 新聞標題標簽內的for屬性
print(element1.get_attribute("for"))
# 新聞標題選擇框是否被選中
print(element2.is_selected())
結果:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。