Angular基础知识学习(一)

hresh 614 0

Angular基础知识学习(一)

属性、元素操作以及指令

普通数据

新建 news 组件,首先在 news.component.ts 文件中定义变量:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-news',
  templateUrl: './news.component.html',
  styleUrls: ['./news.component.css']
})
export class NewsComponent implements OnInit {

  title = 'Hello hresh';

  public name: any = 'hresh';

  content: any = '<h3>Hello Java</h3>';

  msg = '中国,你好';

  constructor() {
    this.msg = '你好中国';

  }

  ngOnInit(): void {
  }

}

在 html 文件中定义标签来获取定义的变量并显示:

<div>
  <p>news works!</p>
    <!--数据文本绑定-->
  <h3>{{title}}</h3>

  <hr />
  <h1>{{content}}</h1>

  <br>
    <!--绑定 html-->
  <span [innerHTML]="content"></span>

  <br>
  <h2>{{msg}}</h2>

  <br>

  1+1={{1+1}}
</div>

效果图如下:

Angular基础知识学习(一)

图片展示

图片资源可以是本地资源,也可以从网上获取,在 html 文件中做如下配置:

  <h3>引入图片</h3>

  <img src="assets/images/10001.png" alt="Angular基础知识学习(一)" alt="hello" />

  <hr>
  <img [src]="picUrl" />
  <img src="{{picUrl}}" />

本地静态资源存放位置如下:

Angular基础知识学习(一)

网上图片资源链接可以在 argular01.component.ts 中定义:

public picUrl = 'https://cn.bing.com/th?id=OIP.bbd7bi181qua_NdZzguE3QHaE6&pid=Api&rs=1';

网页展示图如下:

Angular基础知识学习(一)

模板引用变量

模板引用变量 通常是对模板中 DOM 元素的引用。它还可以引用指令(包含组件)、元素、TemplateRef 或 Web Component 。

使用井号(#)声明模板引用变量。以下模板引用变量 #phone 会在 input 元素上声明了一个 phone 变量。

<input #phone placeholder="phone number" />

<!-- lots of other elements -->

<!-- phone refers to the input element; pass its `value` to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>

模板引用变量的范围是整个模板。因此,不要在同一模板中多次定义相同的变量名,因为它在运行时的值将不可预测。

替代语法

你也可以用 ref- 前缀代替 #。 下面的例子中就用把 fax 变量声明成了 ref-fax 而不是 #fax

<input ref-fax placeholder="fax number" />
<button (click)="callFax(fax.value)">Fax</button>

NgFor

ngFor 指令迭代父组件的 items 属性所返回的 items 数组,并在每次迭代期间将 item 设置为该数组中的当前条目。 NgFor 指令上下文中的 index 属性在每次迭代中返回该条目的从零开始的索引。 您可以在模板输入变量中捕获 index,并在模板中使用它。

同样在 news 组件中,首先定义数组内容:

nums: any[] = [111, 2222, 333];
public values: Array<string> = ['111', '222', '333'];

userList: any[] = [
    {
        name : 'hresh',
        age : 22
    },
    {
        name : 'hresh2',
        age : 22
    },
    {
        name : 'hresh3',
        age : 22
    }
]

cars: any[] = [
    {
        name: '宝马',
        list: [
            {
                title: 'x1',
                price: '30万'
            },
            {
                title: 'x2',
                price: '30万'
            },
            {
                title: 'x3',
                price: '30万'
            }
        ]
    },
    {
        name: '奔驰',
        list: [
            {
                title: 'x1',
                price: '30万'
            },
            {
                title: 'x2',
                price: '30万'
            },
            {
                title: 'x3',
                price: '30万'
            }
        ]
    }
]

在 html 文件中添加内容:

  <ul>
    <li *ngFor="let item of nums">
      {{item}}
    </li>
  </ul>

  <br>

  <ul>
    <li *ngFor="let item of userList">
      {{item.name}}---{{item.age}}
    </li>
  </ul>

  <br>
  <ul>
    <li *ngFor="let item of cars">
      {{item.name}}
      <ul>
        <li *ngFor="let car of item.list">
          {{car.title}}----{{car.price}}
        </li>
      </ul>
    </li>
  </ul>

效果如下:

Angular基础知识学习(一)

trackBy*ngFor

比如有这样一个例子:

import{ Component } from '@angular/core';

@Component({
 selector: 'trackBy-test',
 template: `
 <ul><li *ngFor="let item of items;>{{item.name}}</li></ul>
 <button (click)="getItems()">Get Items</button>
 `
})
export class TrackByCmp{
 items: any[]=[];
 constructor(){
  this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'3',name:'Kitty'}];
 }
 getItems(){
  this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'4',name:'Mac'},{id:'5',name:'John'}];
 }
}

有时你会需要改变这个集合,比如从后端接口返回了新的数据。那么问题来了,Angular 不知道怎么跟踪这个集合里面的项,不知道哪些该添加哪些该修改哪些该删除。结果就是,Angular 会把该集合里的项全部移除然后重新添加。就像这样:

Angular基础知识学习(一)

这样做的弊端是会进行大量的 DOM 操作,而 DOM 操作是非常消耗性能的。

那么解决方案是,为*ngFor 添加一个 trackBy 函数,告诉 Angular 该怎么跟踪集合的各项。trackBy 函数需要两个参数,第一个是当前项的 index,第二个是当前项,并返回一个唯一的标识,就像这样:

import{ Component } from '@angular/core';

@Component({
 selector: 'trackBy-test',
 template: `
 <ul><li *ngFor="let item of items;trackBy: trackByIndex">{{item.name}}</li></ul>
 <button (click)="getItems()">Get Items</button>
 `
})
export class TrackByCmp{
 items: any[]=[];
 constructor(){
  this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'3',name:'Kitty'}];
 }
 getItems(){
  this.items = [{id:'1',name:'Tom'},{id:'2',name:'Jerry'},{id:'4',name:'Mac'},{id:'5',name:'John'}];
 }
trackByIndex(index, item){
  return index;
 }
}

修改之后,Angular 就知道哪些项变动了:

Angular基础知识学习(一)

关于 trackBy 的更多讲解可以参考:Angular-使用好NgForOf的trackBy带来性能上的提升

NgSwitch和NgIf

首先需要在 argular01.component.ts 中定义相关数据内容:

nums: any[] = [111, 222, 333];

flag = false;

order = 1;

html 文件内容如下:

  <h3>循环,显示数据的索引</h3>
  <div>
    <ul>
      <li *ngFor="let item of nums; let key =index">
        <span *ngIf="key == 1" class="red">{{key+1}}----{{item}}</span>
        <span *ngIf="key != 1">{{key+1}}----{{item}}</span>
      </li>
    </ul>
  </div>


  <br>
  <h3>判断</h3>

  <div *ngIf="flag">
    <p>我是一个P标签</p>
  </div>
  <div *ngIf="!flag">
    <p>我是一个PP标签</p>
  </div>
  <br>

  <h3>NgSwitch</h3>
  <span [ngSwitch]="order">
    <p *ngSwitchCase="1">
      1111111111
    </p>
    <p *ngSwitchCase="2">
      2222222222222
    </p>
    <p *ngSwitchDefault>
      00000000000
    </p>
  </span>

上述内容除了介绍 ngIf 和 ngSwitch 的用法,还提到关于循环索引的定义(索引从0开始),同 ngIf 配合使用。

网页效果图如下:

Angular基础知识学习(一)

NgClass和NgStyle

ngClass 同时添加或删除几个 CSS 类。

<div>
  <div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>

  <div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
  <div [class]="isSpecial ? 'special2' : ''">This div is special</div>
</div>

考虑一个 setCurrentClasses() 组件方法,该方法设置一个组件属性 currentClasses,该对象具有一个根据其他三个组件属性的 true / false 状态来添加或删除三个 CSS 类的对象。该对象的每个键(key)都是一个 CSS 类名。如果要添加上该类,则其值为 true,反之则为 false

home2.component.ts

  canSave = true;
  isUnchanged = true;
  isSpecial = true;
  constructor() { }

  ngOnInit(): void {
    this.setCurrentClasses();
  }

  setCurrentClasses() {
    this.currentClasses = {
      'saveable': this.canSave,
      'modified': !this.isUnchanged,
      'special': this.isSpecial
    };
  }

CSS 样式:

.saveable{
  background-color: blue;
}
.modified{
  font-size: 21px;
}

.special{
  font-weight: 200;
}

.special2{
  font-weight: 200;
}

页面测试:

Angular基础知识学习(一)

从上述例子可以看出,当添加单个类时,使用类绑定和 Ngclass 效果是一致的。所以官方文档推荐: 要添加或删除单个类,请使用类绑定而不是 NgClass

使用 NgStyle 根据组件的状态同时动态设置多个内联样式。

  <div [ngStyle]="currentStyles">
    This div is initially italic, normal weight, and extra large (24px).
  </div>

  <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">
    This div is x-large or smaller.
  </div>

下面的例子是一个 setCurrentStyles() 方法,它基于该组件另外三个属性的状态,用一个定义了三个样式的对象设置了 currentStyles 属性。

  currentStyles: any = {};

  canSave = true;
  isUnchanged = true;
  isSpecial = true;
  constructor() { }

  ngOnInit(): void {
    this.setCurrentStyles();
  }

  setCurrentStyles() {
    // CSS styles: set per current state of component properties
    this.currentStyles = {
      'font-style': this.canSave ? 'italic' : 'normal',
      'font-weight': !this.isUnchanged ? 'bold' : 'normal',
      'font-size': this.isSpecial ? '24px' : '12px'
    };
  }

页面测试:

Angular基础知识学习(一)

同 ngClass 一样,官方文档同样推荐设置单个样式值采用样式绑定,设置多个内联样式,请使用 NgStyle 指令 。

管道

管道是格式化字符串、金额、日期和其它显示数据的好办法

Angular 自带了很多管道,比如 date 管道和 currency 管道,完整的列表参见 Pipes API 列表。你也可以自己定义一些新管道。

birthday.component.ts 文件中设置如下:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-birthday',
  templateUrl: '
    <p>The hero's birthday is {{ birthday | date:format }}</p>
    <button (click)="toggleFormat()">Toggle Format</button>
  '
})
export class BirthdayComponent implements OnInit {

  birthday = new Date(1988, 3, 15); // April 15, 1988
  toggle = true; // start with true == shortDate

  constructor() { }

  ngOnInit(): void {
  }

  get format()   { return this.toggle ? 'shortDate' : 'fullDate'; }
  toggleFormat() { this.toggle = !this.toggle; }
}


网页展示效果:

Angular基础知识学习(一)

安全导航运算符( ? )和空属性路径

Angular 安全导航运算符 ? 可以对在属性路径中出现 nullundefined 值进行保护。在这里,如果 itemnull ,它可以防止视图渲染失败。

<p>The item name is: {{item?.name}}</p>

如果 itemnull,则视图仍然渲染,但显示的值为空白;您只会看到 “The item name is:” ,后面没有任何内容。

考虑接下来这个带有 nullItem 的例子。

The null item name is {{nullItem.name}}

由于没有安全导航运算符,并且 nullItemnull ,因此 JavaScript 和 Angular 会引发空指针错误并中断 Angular 的渲染过程:

content_copyTypeError: Cannot read property 'name' of null.

但是,有时在某些情况下,属性路径中的 null 值可能是可接受的,尤其是当该值开始时为空但数据最终会到达时。

使用安全导航运算符 ?,当 Angular 表达式遇到第一个空值时,它将停止对表达式的求值,并渲染出无错误的视图。

绑定语法

数据绑定是一种机制,用来协调用户可见的内容,特别是应用数据的值。 虽然也可以手动从 HTML 中推送或拉取这些值,但是如果将这些任务转交给绑定框架,应用就会更易于编写、阅读和维护。 您只需声明数据源和目标 HTML 元素之间的绑定关系就可以了,框架会完成其余的工作。

Angular 提供了多种数据绑定方式。绑定类型可以分为三类,按数据流的方向分为:

  • 数据源到视图
  • 视图到数据源
  • 双向:视图到数据源到视图

Angular基础知识学习(一)

绑定类型与绑定目标

数据绑定的目标是 DOM 中的对象。 根据绑定类型,该目标可以是 Property 名(元素、组件或指令的)、事件名(元素、组件或指令的),有时是 Attribute 名。下表中总结了不同绑定类型的目标。 关于这一部分会结合例子进行演示,没有固定篇幅进行讲解,详细内容可以参考:Angular模块语法

Angular基础知识学习(一)

事件

普通点击事件

首先修改 html 文件:

<h3>事件</h3>
<button (click)="run()">执行事件</button>
<br>
<br>
<button (click)="getData()">获取数据</button>
<br>
<br>
<strong>{{title}}</strong>
<br>
<br>
<button (click)="setData()">设置数据</button>
<br>
<br>
<button (click)="runEvent($event)" id="btn">执行方法获取事件对象</button>
<br>

然后在 argular01.component.ts 文件中添加实现方法

  title = '这是一个主题';

  keywords = '这是一个input'

  run() {
    alert('hello');
  }
  constructor() { }

  ngOnInit(): void {
  }

  getData() {
    alert(this.title);
  }
  setData() {
    this.title = '新的主题';
  }
  runEvent(e) {
    var dom = e.target;
    dom.style.color = 'red';
  }

网页展示效果如下:

Angular基础知识学习(一)

表单事件

html 文件:

<h3>表单事件 事件对象</h3>
<!--<input type="text" (keydown)="keydown()">-->
<br>
<input type="text" (keydown)="keydown(event)">
<br>
<input type="text" (keyup)="keyup(event)" >

然后在 argular01.component.ts 文件中添加实现方法

  keydown(e) {
    console.log(e.target.value);
  }
  keyup(e) {
    if (e.keyCode == 13) {
      console.log('敲了一下回车');
    }
  }

网页展示效果如下:

Angular基础知识学习(一)

补充语句与事件绑定的例子,语句上下文可以引用模板自身上下文中的属性,在上面例子中把模板的$event对象传给了组件中的事件处理方法,还可以将模板输入变量 (let key)和模板引用变量 (#inputDom) 传到组件方法中。

    <input type="text" #inputDom (input)="getData2(inputDom.value)" />
    <br>
    <div>
      <ul>
        <li *ngFor="let item of nums; let key =index">
          <span>{{key+1}}----{{item}}</span> 
          <button (click)="delete(key)">X</button>
        </li>
      </ul>
    </div>

事件方法定义如下:

  getData2(data: any) {
    console.log(data);
  }

  delete(key) {
    this.nums.splice(key, 1);
  }

页面测试:

Angular基础知识学习(一)

双向数据绑定

双向绑定会做两件事:

  1. 设置特定的元素属性。
  2. 监听元素的变更事件。

    Angular 为此提供了一种特殊的双向数据绑定语法 [()][()] 语法将属性绑定的括号 [] 与事件绑定的括号 () 组合在一起。

首先在 app.module.ts 里面引入 NgModule 并声明。

// 浏览器解析的模块
import { BrowserModule } from '@angular/platform-browser';
// Angular核心模块
import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms';

// 根组件
......

// @NgModule装饰器,@NgModule接受一个元数据对象,告诉 Angular 如何编译和启动应用
@NgModule({
  declarations: [// 配置当前项目运行的组件
    AppComponent, NewsComponent, Argular01Component, FormComponent, SearchComponent
  ],
  imports: [// 配置当前模块运行依赖的其他模块
    BrowserModule,
    FormsModule
  ],
  providers: [StorageService],
  bootstrap: [AppComponent]
})
export class AppModule { }


html 文件内容:

    <h3>双向绑定</h3>
    <p><input type="text" [(ngModel)]="keywords"></p>

    <span>{{keywords}}</span>
    <br>
    <br>
    <span><button (click)="upkeywords()">修改数据</button></span>


最后在 argular01.component.ts 定义变量和方法。

keywords = '这是一个input';

upkeywords() {
    this.keywords = '改变后的数据';
}

网页展示效果:

Angular基础知识学习(一)

关于 input 框双向数据绑定,在上面介绍的 (input)="getData2(inputDom.value)"方法,修改一下也可以实现同样的效果。

$event 和事件处理语句

html 文件:

<p>input数据绑定:<input [value]="keywords"
                    (input)="keywords=$event.target.value" ></p>
<span>{{keywords}}</span>

上面的代码在把输入框的 value 属性绑定到 name 属性。 要监听对值的修改,代码绑定到输入框的 input 事件。 当用户造成更改时,input 事件被触发,并在包含了 DOM 事件对象 ($event) 的上下文中执行这条语句。

要更新 name 属性,就要通过路径 $event.target.value 来获取更改后的值。

页面测试:

Angular基础知识学习(一)

Form表单

新建一个组件:

ng g component components/form

首先在 app.module.ts 里面引入 NgModule 并声明。

1、form.component.html

  <h2>人员登记系统</h2>

  <!--讲解表单 input、checkbox、radio、select、textarea实现在线预约功能-->
  <div class="people_list">
    <ul>
      <li>
        姓 名:
        <input type="text" [(ngModel)]="peopleInfo.username" id="username" class="form_input">
      </li>


      <li>
        性 别:
        <input type="radio" value="1" name="sex" id="man" [(ngModel)]="peopleInfo.sex"> <label for="man">男</label>
        <input type="radio" value="2" name="sex" id="woman" [(ngModel)]="peopleInfo.sex"> <label for="woman">女</label>
      </li>

      <li>
        城 市:
        <select [(ngModel)]="peopleInfo.city">
          <option *ngFor="let item of peopleInfo.cities">
            {{item}}
          </option>
        </select>
      </li>
      <li>
        爱 好:
        <span *ngFor="let item of peopleInfo.hobbies;let key=index" >
          <input type="checkbox" [id]="'check'+key" [(ngModel)]="item.checked"><label [for]="'check'+key">{{item.title}}</label>
            
        </span>
      </li>
      <li>
        备 注:
        <textarea [(ngModel)]="peopleInfo.remark" cols="30" rows="2"></textarea>
      </li>

      <br>
      <button (click)="getData()">获取表单的值</button>

      <pre>
        {{peopleInfo | json}}
      </pre>
    </ul>
  </div>

2、form.component.css

ul,ol{
  list-style-type: none;
}
*{
  margin: 0px;
  padding:0px;
}

h2{
  text-align: center;
}
.people_list{
  width: 400px;
  margin: 40px auto;

  padding: 20px;

  border: 1px solid #eeeeee;

}

.people_list li{
  height: 50px;

  line-height: 50px;
}

.form_input{
  width: 300px;
  height: 28px;
}

3、form.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  peopleInfo: any = {
    username: '',
    sex: '1',
    cities: ['北京', '上海', '深圳'],
    city: '上海',
    hobbies: [
      {
        title: '吃饭',
        checked: false
      },
      {
        title: '睡觉',
        checked: false
      },
      {
        title: '写代码',
        checked: true
      }
    ],
    remark: ''
  }
  constructor() { }

  ngOnInit(): void {
  }

  getData() {
    console.log(this.peopleInfo);
  }
}

4、网页展示效果

Angular基础知识学习(一)

5、小结

对于性别单选和爱好多选框,勾选时前台发生了什么变化,双向数据绑定了什么样的数据。

Angular基础知识学习(一)

上面动图中注意观察 ng-reflect-model 值的变化。

搜索

新建一个组件:

ng g component components/search

首先在 app.module.ts 里面引入 NgModule 并声明。

1、search.component.html

<h2>search</h2>

<div class="search">
  <input type="text" [(ngModel)]="keyWord" (keyup)="keyup($event)">      <button (click)="search()">搜索</button>

  <hr>
  <ul>
    <li  *ngFor="let item of keyWordsOld;let key=index"> {{item}} ----- <button (click)="delete(key)">X</button></li>
  </ul>
</div>

2、search.component.ts

keyWord: any = '';

keyWordsOld: any[] = [];

keyup(e) {
    if (e.keyCode === 13){
        if (this.keyWordsOld.indexOf(this.keyWord) === -1) {
            this.keyWordsOld.push(this.keyWord);
        }
        this.keyWord = '';
    }
}

search() {
    if (this.keyWordsOld.indexOf(this.keyWord) == -1) {
        this.keyWordsOld.push(this.keyWord);
    }
    this.keyWord = '';
}

delete(key) {
    this.keyWordsOld.splice(key, 1);
}

3、网页展示效果

Angular基础知识学习(一)

结合我们日常使用淘宝京东的习惯,搜索记录都会保留下来,这就涉及到数据持久化,后续会整合讲解。

TodoList(待办事项和已完成事项)

练习双向绑定来实现代办事项和已完成事项的转变。

1、search.component.html

<h2>搜   索todoList</h2>

<div class="search">
  <input type="text" [(ngModel)]="product" (keyup)="add($event)" >

  <hr>
  待办事项
  <ul>
    <li *ngFor="let item of products;let key=index" [hidden]="item.status == 1">
      <input type="checkbox" [(ngModel)]="item.status">{{item.status}} ----  {{item.title}}
      ----- <button (click)="deleteWay(key)">X</button>
    </li>
  </ul>
  <hr>
  已办事项
  <ul>
    <li *ngFor="let item of products;let key=index" [hidden]="item.status == 0">
      <input type="checkbox" [(ngModel)]="item.status" >{{item.status}} ----  {{item.title}}
      ----- <button (click)="deleteWay(key)">X</button>
    </li>
  </ul>
      <hr>
  <div>
    <pre>
      {{products | json}}
    </pre>
  </div>
</div>

2、search.component.ts

product: any = '';
products: any[] = [];

add(e) {
    // tslint:disable-next-line:triple-equals
    if (e.keyCode == 13) {
        if (!this.equalProduct(this.products, this.product)) {
            this.products.push({
                title: this.product,
                status: 0
            });
            this.product = '';
        } else {
            alert('数据已存在');
            this.product = '';
        }
    }
}

deleteWay(key) {
    this.products.splice(key, 1);
}

equalProduct(products: any[], value: any) {

    if (!value || value === '') {
        return false;
    }

    // tslint:disable-next-line:prefer-for-of
    for (let i = 0; i < products.length; i++) {
        // tslint:disable-next-line:triple-equals
        if (products[i].title == value) {
            return true;
        }
    }
    return false;
}

3、网页展示效果

Angular基础知识学习(一)

发表评论 取消回复
表情 图片 链接 代码

分享