聊聊angular10中模板如何进行数据绑定?
绑定语法概览
绑定语法归纳起来大概有三种(基础)
- model => view (单向:插值、属性绑定、样式绑定)
- view => model(单向:事件绑定)
- view => model(双向:ngModule)
【相关教程推荐:《Angular教程》】
!-- model => view --> { { exPression} } [target]="exPRession"bind-target="expression"p> { { msg } } /p> // 插值表达式img [src]="heROImageUrl"> // 属性绑定app-hero-detail [hero]="currentHero"> /app-hero-detail> // 组件通过属性绑定的方式传参div [ngClass]="{ 'sPEcial': isSpecial} "> /div> // 样式绑定div [class.special]="isSpecial"> Special/div> // class绑定button [style.color]="isSpecial ? 'red' : 'green'"> // style绑定button [attr.aria-label]="help"> help/button> // Attribute绑定!-- view => model --> (target)="statement"on-target="statement"button (click)="onSave()"> Save/button> // 元素事件app-hero-detail (deleteRequest)="deleteHero()"> /app-hero-detail> // 组件事件,用于监听子组件传递过来的参数div (myClick)="clicked=$event" clickable> click me/div> // 指令事件!-- view => model --> [(target)]="expression"bindon-target="expression"input [(ngModel)]="name"> // 双向数据绑定
HTML attribute 与 DOM property 的对比(很重要,加强理解)
理解 HTML 属性和 DOM 属性之间的区别,是了解 Angular 绑定如何工作的关键。Attribute 是由 HTML 定义的。Property 是从 DOM(文档对象模型)节点访问的
- 一些 HTML Attribute 可以 1:1 映射到 Property;例如,“ id”。
- 某些 HTML Attribute 没有相应的 Property。例如,aria-* colSpan rowSpan。
- 某些 DOM Property 没有相应的 Attribute。例如,textContent。
重要的是要记住,HTML Attribute 和 DOM Property 是不同的,就算它们具有相同的名称也是如此。 在 Angular 中,HTML Attribute 的唯一作用是初始化元素和指令的状态。
模板绑定使用的是 Property 和事件,而不是 Attribute。
编写数据绑定时,你只是在和目标对象的 DOM Property 和事件打交道。
注意:
该通用规则可以帮助你建立 HTML Attribute 和 DOM Property 的思维模型: 属性负责初始化 DOM 属性,然后完工。Property 值可以改变;Attribute 值则不能。
此规则有一个例外。 可以通过 setattribute() 来更改 Attribute,接着它会重新初始化相应的 DOM 属性。
案例1:input
input type="text" value="Sarah">
当浏览器渲染input时,它会创建一个对应的 DOM 节点,其 value Property 已初始化为 “Sarah”。
当用户在 input 中输入 Sally 时,DOM 元素的 value Property 将变为 Sally。 但是,如果使用 input.getAttribute('value') 查看 HTML 的 Attribute value,则可以看到该 attribute 保持不变 —— 它返回了 Sarah。
HTML 的 value 这个 attribute 指定了初始值;DOM 的 value 就是这个 property 是当前值。
案例2:禁用按钮
disabled Attribute 是另一个例子。按钮的 disabled Property 默认为 false,因此按钮是启用的。
当你添加 disabled Attribute 时,仅仅它的出现就将按钮的 disabled Property 初始化成了 true,因此该按钮就被禁用了。
button disabled> test Button/button>
添加和删除 disabled Attribute 会禁用和启用该按钮。 但是,Attribute 的值无关紧要,这就是为什么你不能通过编写 仍被禁用 来启用此按钮的原因。
要控制按钮的状态,请设置 disabled Property,
input [disabled]="condITion ? true : false"> input [attr.disabled]="condition ? 'disabled' : null">
模板/插值表达式 { { } } (基础,掌握)
模版中除了绑定变量,还能绑定方法
模版中还可以写些简单的逻辑,比如判断或运算
import { component } From '@angular/core'; @Component({ selector: 'app-root', template: ` p> 变量绑定:{ { title } } /p> p> 方法绑定:{ { getVal } } /p> p> 方法绑定:{ { getVal2() } } /p> p> 简单运算 { { 1 + 1 } } ./p> p> 简单运算 { { price * 0.7 } } ./p> p> 简单运算:{ { gender === 0 ? '男':'女' } } /p> p> 与方法结合 { { price * 0.7 + getVal } } ./p> p> 与方法结合 { { price * 0.7 + getVal2() } } ./p> `,} )export class AppComponent { title = "模板绑定"; price = 30; gender = 0; get getVal(): number { //es6新语法,函数可以当做变量来使用 return 20; } getVal2(): number { return 33; } }
当使用模板表达式时,请遵循下列指南:
- 非常简单
- 执行迅速
- 没有可见的副作用(即模版中的逻辑不能改变组件的变量)
属性绑定(基础,掌握)
绑定图片
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` img src="../assets/images/maDAO.jpg" alt="madao" /> img [src]="madaoSrc" alt="madao" /> // 推荐 img bind-src="madaoSrc" alt="madao" /> `, styles: []} )export class AppComponent { madaoSrc = '../assets/images/madao.jpg'; }
绑定普通属性
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` img [src]="user.pic" [alt]="user.name" /> table class="table-bordered"> tr> th> name/th> th> phone/th> th> age/th> /tr> tr> td> 张三/td> td> 13398490594/td> td> 33/td> /tr> tr> td [colSpan]="colSpan"> 李四/td> // 注意colSpan和colspan td> 15079049984/td> td> 22/td> /tr> /table> button class="BTn btn-Primary" [disabled]="isDisabled"> click/button> `, styles: []} )export class AppComponent { madaoSrc = '../assets/images/madao.jpg'; user = { name: 'madao', pic: this.madaoSrc } ; colSpan = 2; isDisabled = false; }
绑定自定义属性
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` span [attr.data-title]="customTitle"> 一行文字/span> span [attr.title]="customTitle"> test title/span> span [title]="customTitle"> test title/span> `, styles: []} )export class AppComponent { madaoSrc = '../assets/images/madao.jpg'; customTitle = 'bbb'; }
使用插值表达式(不推荐)
插值也可以用于属性,但常规做法还是用中括号[],建议整个项目保持风格统一
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` img src="{ { user.pic } } " alt="{ { user.name } } " /> `, styles: []} )export class AppComponent { madaoSrc = '../assets/images/madao.jpg'; user = { name: 'madao', pic: this.madaoSrc } ; }
样式绑定(属于属性绑定,基础,掌握)
绑定单个样式
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` button type="button" class="btn" [class.btn-primary]="theme === 'primary'"> Primary/button> button type="button" class="btn" [class.btn-secondary]="true"> secondary/button> button type="button" class="btn" [class.btn-success]="isSuccess"> success/button> button type="button" class="btn" [class.btn-danger]="'啦啦啦'"> danger/button> button type="button" class="btn" [class.btn-danger]="0"> danger/button> //false button type="button" class="btn" [class.btn-danger]="undefined"> danger/button> //false `, styles: []} )export class AppComponent { theme = 'primary'; isSuccess = true; }
绑定多个class
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` button type="button" [class]="btnCls"> btnCls/button> button type="button" [class]="btnCls2"> btnCls2/button> button type="button" [class]="btnCls3"> btnCls3/button> !-- 也可以用内置指令ngClass --> button type="button" [ngClass]="btnCls"> btnCls/button> button type="button" [ngClass]="btnCls2"> btnCls2/button> button type="button" [ngClass]="btnCls3"> btnCls3/button> `, styles: []} )export class AppComponent { btnCls = 'btn btn-primary'; btnCls2 = ['btn', 'btn-success']; btnCls3 = { btn: true, 'btn-info': true } ; }
绑定单个style
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` p [style.color]="'#f60'"> 一段文字/p> p [style.height]="'50px'" [style.border]="'1px solid'"> 设置高度/p> p [style.height.px]="50" [style.border]="'1px solid'"> 设置高度/p> `, styles: []} )export class AppComponent { }
绑定多个style
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` p [style]="style1"> style1/p> p [style]="style2"> style2/p> p [style]="style3"> style3/p> !-- 也可以用内置指令ngStyle, 但不推荐,以后可能会弃用 --> !-- p [ngStyle]="style1"> style1/p> --> !-- p [ngStyle]="style2"> style2/p> --> !-- ngStyle只接收对象 --> p [ngStyle]="style3"> style3/p> `, styles: []} )export class AppComponent { style1 = 'width: 200px; height: 50px; text-align: center; border: 1px solid; '; style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题 style3 = { width: '200px', height: '50px', 'text-align': 'center', border: '1px solid' } ; }
绑定优先级
- 某个类或样式绑定越具体,它的优先级就越高
- 绑定总是优先于静态属性
事件绑定(基础,掌握)
基本用法
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` button type="button" class="btn btn-primary" (click)="onClick()"> Primary/button> `, styles: []} )export class AppComponent { onClick() { console.LOG('onClick'); } }
事件对象
$event 就是原生的事件对象
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` button type="button" class="btn btn-primary" (click)="onClick($event)"> Primary/button> `, styles: []} )export class AppComponent { onClick(event: MouseEvent) { console.log('onClick', event.target); //直接用event.target.value会报错,要用类型断言 console.log((event.target as HTMLInputElement).value) } }
事件捕获或事件冒泡
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` div style="width:200px; height:200px; background-color:red; " (click)="parentClick()"> !--div style="width:100px; height:100px; background-color:blue; " (click)="chilrenClick($event)"> /div> --> div style="width:100px; height:100px; background-color:blue; " (click)="$event.stopPropagation()"> /div> //可以在html使用一些简单的语法 /div> `, styles: []} )export class AppComponent { parentClick() { console.log('parentClick'); } chilrenClick(event: MouseEvent) { event.stopPropagation(); //阻止事件冒泡 console.log('chilrenClick'); } }
输入输出属性(主要是子传父,通过自定义事件)
输入属性
子组件
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-root', template: `p> Today's item: { { item} } /p> `} )export class ItemDetailComponent { @Input() item: string; }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail [item]="currentItem"> /app-item-detail> `,} )export class AppComponent { currentItem = 'Television'; }
输出属性
- 通过 new EventEmitter() 自定义一个事件;
- 调用 EventEmitter.emit(data) 发出事件,传入数据;
- 父指令通过监听自定义事件,并通过传入的 $event 对象接收数据。
子组件
import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-root', template: `label> Add an item: input #newItem> /label> button (click)="addNewItem(newItem.value)"> Add to parent's list/button> `,} )export class ItemOutputComponent { @Output() newItemEvent = new EventEmitterstring> (); //子传父,输出属性 addNewItem(value: string) { this.newItemEvent.emit(value); //自定义事件触发 } }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-output (newItemEvent)="addItem($event)"> /app-item-output> //监听自定义事件 `,} )export class AppComponent { items = ['item1', 'item2', 'item3', 'item4']; addItem(newItem: string) { this.items.push(newItem); } }
在元数据中声明输入和输出属性
固然可以在 @Directive 和 @Component 元数据中声明 inputs 和 outputs,但不推荐提供别名
@Input()和@Output()可以接收一个参数,作为变量的别名,那么父组件中只能用别名绑定
子组件
import { Component, Input, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'app-root', template: `p> Today's item: { { item} } /p> `} )export class ItemDetailComponent { @Input('aliasItem') item: string; @Output('newItem') newItemEvent = new EventEmitterstring> (); addNewItem(value: string) { this.newItemEvent.emit(value); } }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail [aliasItem]="currentItem" //注意是绑定的别名 (newItem)="addItem($event)"> /app-item-detail> //注意是监听的别名 `,} )export class AppComponent { currentItem = 'Television'; items = ['item1', 'item2', 'item3', 'item4']; addItem(newItem: string) { this.items.push(newItem); } }
输入属性一定要用中括号[]绑定?
如果绑定的值是静态的,就不需要[];为了统一风格尽量用上[]
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail item="static item"> /app-item-detail> `,} )export class AppComponent { // currentItem = 'Television'; }
双向绑定(基础,掌握)
先决条件
- 组件的属性绑定
- 组件的事件绑定
- 输入和输出(父子组件通信)
基本的双向绑定
子组件
import { Component, OnInit, ChangedetectionStrategy, EventEmitter, Input, Output} from '@angular/core'; @Component({ selector: 'app-sizer', template: ` div> button class="btn btn-danger" (click)="dec()" title="smaller"> -/button> button class="btn btn-primary" (click)="inc()" title="Bigger"> +/button> label [style.font-size.px]="size"> FontSize: { { size} } px/label> /div> `, styles: [ ], changeDetection: ChangeDetectionStrategy.OnPush} )export class SizerComponent implements OnInit { @Input() size: number | string; // 想要用双向绑定语法,output变量名就一定是输入属性名加上Change @Output() sizeChange = new EventEmitternumber> (); constructor() { } ngOnInit(): void { } dec() { this.resize(-1); } inc() { this.resize(+1); } resize(delta: number) { this.size = Math.min(40, Math.max(8, +this.size + delta)); this.sizeChange.emit(this.size); } }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-sizer [(size)]="fontSizePx"> /app-sizer> div [style.font-size.px]="fontSizePx"> Resizable Text/div> `,} )export class AppComponent { fontSizePx = 16; }
双向绑定工作原理
为了使双向数据绑定有效,@Output() 属性的名字必须遵循 inputChange 模式,其中 input 是相应 @Input() 属性的名字。例如,如果 @Input() 属性为 size ,则 @Output() 属性必须为 sizeChange 。
上面的 sizerComponent 具有值属性 size 和事件属性 sizeChange。 size 属性是 @Input(),因此数据可以流入 sizerComponent 。 sizeChange 事件是一个 @Output() ,它允许数据从 sizerComponent 流出到父组件。
上面例子,有两个方法, dec() 用于减小字体大小, inc() 用于增大字体大小。这两种方法使用 resize() 在最小/最大值的约束内更改 size 属性的值,并发出带有新 size 值的事件。
简写形式
双向绑定语法是属性绑定和事件绑定的组合的简写形式
app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"> /app-sizer>
表单中的双向绑定
因为没有任何原生 HTML 元素遵循了 x 值和 xChange 事件的命名模式,所以与表单元素进行双向绑定需要使用 NgModel
基本使用
根据之前基本的双向绑定知识,[(ngModel)]语法可拆解为:
- 名为ngModel的输入属性
- 名为ngModelChange的输出属性
使用[(ngModule)]双向绑定的前提条件是在模块中引入FormsModule
import { Component} from '@angular/core'; @Component({ selector: 'example-app', template: ` input [(ngModel)]="name" #ctrl="ngModel" required> p> Value: { { name } } /p> p> Valid: { { ctrl.valid } } /p> button (click)="setValue()"> Set value/button> `,} )export class SimpleNgModelComp { name: string = ''; setValue() { this.name = 'Nancy'; } }
input [(ngModel)]="name" /> 上面这行代码相当于:input [value]="name" (input)="name = $event.target.value" />
在表单中的使用
表单中使用[(ngModel)],需要做下面两件事的其中之一
- 给控件加上name属性
- 将ngModelOptions.standalone设为true
form> input [(ngModel)]="value" name="name" /> input [(ngModel)]="value" [ngModelOptions]="{ standalone: true } " /> /form>
注意:表单中使用双向数据绑定,知识点比较多,这里只做简单了解,后续会出专门章节探讨
内置指令
循环指令 *ngFor (非常基础,掌握)
arr:string[] = ['张三','李四','王五']; trackByItems(index: number, item: Item): number { return item.id; } div *ngFor="let item of arr; let i=index" (click)='choseThis(item,i)'> 索引值:{ { i} } -- 内容:{ { item} } /div> //trackBy一般和长列表一起使用,减少dom替换次数,提升性能div *ngFor="let item of items; trackBy: trackByItems"> ({ { item.id} } ) { { item.name} } /div>
条件渲染 *ngIf ngStyle ngClass ngSwitch(非常基础)
isShow: Boolean = true; personState: number = 2; //频繁切换不建议用,频繁加载和移除有较高的性能消耗 (重要)p *ngIf="isShow"> 命令模式/p> // 不频繁切换推荐用p [hidden]="isShow"> 命令模式/p> // 频繁切换推荐用currentStyles = { 'font-style': this.canSave ? 'italic' : 'normal', 'font-weight': !this.isUnchanged ? 'bold' : 'normal', 'font-size': this.isSpecial ? '24px' : '12px'} ; div [ngClass]="isSpecial ? 'special' : ''"> ngClass/div> div [ngStyle]="currentStyles"> ngStyle/div> // 使用样式有2种(style.dispaly 和 class.hidden)p [style.display]="isShow?'block':'none'"> style模式/p> //频繁切换建议用样式p [class.hidden]="isShow"> class模式/p> //匹配多种情况的条件渲染,跟vue的v-if/v-else-if/v-else类似//适合多种状态,显示一种的情况div [ngSwitch] = 'personState'> div *ngSwitchCase="1"> 工作/div> div *ngSwitchCase="2"> 吃饭/div> div *ngSwitchDefault> 睡觉/div> /div>
双向数据绑定指令 [(ngModel)]
//Angular不能直接识别ngModel,需要通过引入模块FormsModule来访问import { FormsModule} from '@angular/forms'; imports: [FormsModule]public name = "张三"; input [(ngModel)] = "name" type="text"> //人工绑定,更好的做法是通过响应式表单绑定input bindon-change="name" type="text"> //备选//属性绑定+事件绑定 = ngModel (重要)input [value]="name" (input)="name=$event.target.value" >
模板引用变量
基本使用
使用井号(#)声明模板引用变量,可以获取DOM 元素、指令、组件、TemplateRef 或 Web Component。
import { Component} from '@angular/core'; @Component({ selector: 'app-tpl-VAR', template: ` input #phone placeholder="phone number" /> button (click)="callPhone(phone.value)"> Call/button> `,} )export class TplVarComponent { constructor() { } callPhone(value: string) { console.log('callPhone', value); } }
ref
还有种写法就是ref, 下面两种写法是一样的
input #fax placeholder="fax number" /> input ref-fax placeholder="fax number" />
引用组件
在组件章节,介绍了获取子组件的属性和方法,有两种方法:本地变量和@ViewChild()
import { Component} from '@angular/core'; @Component({ selector: 'app-tpl-var', template: ` div class="demo-sec"> button class="btn btn-primary" (click)="sizer.inc()"> app inc/button> app-sizer [(size)]="size" #sizer> /app-sizer> size: { { size } } /div> `,} )export class TplVarComponent { size = 16; constructor() { } }
输入和输出
输入属性
子组件
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-root', template: `p> Today's item: { { item} } /p> `} )export class ItemDetailComponent { @Input() item: string; }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail [item]="currentItem"> /app-item-detail> `,} )export class AppComponent { currentItem = 'Television'; }
输出属性
子组件
import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-root', template: `label> Add an item: input #newItem> /label> button (click)="addNewItem(newItem.value)"> Add to parent's list/button> `,} )export class ItemOutputComponent { @Output() newItemEvent = new EventEmitterstring> (); addNewItem(value: string) { this.newItemEvent.emit(value); } }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-output (newItemEvent)="addItem($event)"> /app-item-output> `,} )export class AppComponent { items = ['item1', 'item2', 'item3', 'item4']; addItem(newItem: string) { this.items.push(newItem); } }
在元数据中声明输入和输出属性
固然可以在 @Directive 和 @Component 元数据中声明 inputs 和 outputs,不推荐提供别名。
@Input()和@Output()可以接收一个参数,作为变量的别名,那么父组件中只能用别名绑定子组件
import { Component, Input, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'app-root', template: `p> Today's item: { { item} } /p> `} )export class ItemDetailComponent { @Input('aliasItem') item: string; // decorate the property with @Input() @Output('newItem') newItemEvent = new EventEmitterstring> (); addNewItem(value: string) { this.newItemEvent.emit(value); } }
父组件
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail [aliasItem]="currentItem" (newItem)="addItem($event)"> /app-item-detail> `,} )export class AppComponent { currentItem = 'Television'; items = ['item1', 'item2', 'item3', 'item4']; addItem(newItem: string) { this.items.push(newItem); } }
输入属性一定要用中括号[]绑定?
如果绑定的值是静态的,就不需要[]
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` app-item-detail item="static item"> /app-item-detail> `,} )export class AppComponent { // currentItem = 'Television'; }
管道(基础,掌握)
常用的管道
1、大小写字母转换
str = 'Hello'; str1 = 'World'; p> { { str | uppercase} } -{ { str1 | lowercase} } /p> //str:hello str1:WORLD
2、 日期格式化(经常使用)
today = new Date(); p> 现在的时间是{ { today | date:'yyyy-MM-dd HH:mm:ss'} } /p>
3、保留小数后面多少位下面例子的含义是,3表示最少几位整数,后面的2-4表示最少最少2位小数,最多4位小数,不足补零,小数会四舍五入。
num = 125.156896; p> num保留4位小数的值是:{ { num | number:'3.2-4'} } /p> //125.1569
4、货币转换
count = 5; price = 1.5; p> 数量:{ { count} } /p> // 数据:5p> 价格:{ { price} } /p> // 价格:1.5p> 总价:{ { (price * count) | currency:'¥'} } /p> // 价格:¥7.5
5、字符串截取
name = '只对你说'; p> { { name | slice : 2 : 4} } /p> // 你说
6、json格式化(有时需要看一下数据)
p> { { { name: 'SEMlinker' } | JSON } } /p> // { "name": "semlinker" }
自定义管道
1、创建管道文件
ng g pipe /piper/mypiper
2、在管道文件中写自己的逻辑transform两个参数分别表示传入值和参数
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'multiple'} )export class MypiperPipe implements PipeTransform { transform(value: any, args?: any): any { //value:输入值 args:参数 if(!args){ //无参的情况下 args = 1; } return value*args; } }
注意:通过命令行生成的管道(过滤器),会自动在全局声明;管道传入的参数是在':'冒号后面表示
更多编程相关知识,请访问:编程视频!!
以上就是聊聊angular10中模板如何进行数据绑定?的详细内容,更多请关注其它相关文章!
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: 聊聊angular10中模板如何进行数据绑定?
本文地址: https://pptw.com/jishu/591995.html