Angular基础知识学习(二)下

简介: Angular基础知识学习(二)下

子组件通过Output给父组件传值



1、news.component.html,


<app-footer (outter)="run($event)"></app-footer>
<br>
<hr>
<br>
<h2>我是news组件</h2>
复制代码


2、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 {
  constructor() {
  }
  ngOnInit(): void {
  }
  run(e) {
    console.log(e);
    alert('我是news组件的方法');
  }
}
复制代码


3、footer.component.html


<h2>我是footer组件</h2>
<br>
<button (click)="sendMsg()">子组件广播事务</button>
复制代码


4、footer.component.ts


import {Component, OnInit, Output, EventEmitter} from '@angular/core';
@Component({
  selector: 'app-footer',
  templateUrl: './footer.component.html',
  styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
  @Output() private outter = new EventEmitter();
  constructor() {
  }
  ngOnInit(): void {
  }
  sendMsg() {
    this.outter.emit('我是footer组件的数据');
  }
}
复制代码


5、网页运行效果如下:


1.jpg


6、小结


子组件给父组件传值,即父组件接收子组件的属性,大致分为以下几步:


  1. 子组件引入 Output、EventEmitter 模块;
  2. 子组件将要传输的数据封装在 outter 中;
  3. 父组件页面嵌套子组件页面,子组件声明时需要将 outter 指向父组件中的某个方法,注意接收数据;


父子组件相互通信


子组件 sizer.component.ts:


import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
  selector: 'app-sizer',
  templateUrl: './sizer.component.html',
  styleUrls: ['./sizer.component.css']
})
export class SizerComponent implements OnInit {
  @Input() size: number | string;
  @Output() sizeChange = new EventEmitter<number>();
  constructor() { }
  ngOnInit(): void {
  }
  inc() {
    this.resize(+1);
  }
  dec() {
    this.resize(-1);
  }
  resize(delta: number) {
    this.size = Math.min(40, Math.max(8, +this.size + delta));
    this.sizeChange.emit(this.size);
  }
}
复制代码


sizer.component.html:


<h2>子组件</h2>
<div>
  <button (click)="dec()" title="smaller">-</button>&nbsp;&nbsp;
  <button (click)="inc()" title="bigger">+</button>
  <br>
  <br>
  <label [style.font-size.px]="size">FontSize: {{size}}px</label>
</div>
复制代码


size 的初始值来自属性绑定的输入值。单击按钮可在最小值/最大值范围内增大或减小 size,然后带上调整后的大小发出 sizeChange 事件。


Home2Component.fontSize 首先传递给 SizerComponent$event 变量包含了 SizerComponent.sizeChange 事件的荷载。 当用户点击按钮时,Angular 将 $event 赋值给 Home2Component.fontSizePx。 父组件 home2.component.html:


<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
<h2>父组件</h2>
<div [style.font-size.px]="fontSizePx">Resizable Text</div>
复制代码


Home2Component.fontSizePx 建立初始 SizerComponent.size 值。


home2.component.ts:


fontSizePx = 16;
复制代码


页面测试:


1.jpg


上述父子组件之间通信的关键在于:


<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
复制代码


此处还可以通过双向绑定来实现, 双向绑定语法实际上是属性绑定和事件绑定的语法糖,所以还可以改为:


<app-sizer [(size)]="fontSizePx"></app-sizer>
复制代码


Home2Component.fontSize 被双向绑定到 SizerComponent


Rxjs异步数据流编程


介绍

RxJS 是 ReactiveX 编程理念的 JavaScript 版本。ReactiveX 来自微软,它是一种针对异步数据流的编程。


简单来说,它将一切数据,包括 HTTP 请求,DOM 事件或者普通数据等包装成流

的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。


RxJS 是一种针对异步数据流编程工具,或者叫响应式扩展编程;可不管如何解释 RxJS 其目标就是异步编程,Angular 引入 RxJS 为了就是让异步可控、更简单。


RxJS 里面提供了很多模块。这里我们主要给大家讲 RxJS 里面最常用的 Observable 和

fromEvent。


参考手册:https://www.npmjs.com/package/rxjs

中文手册:https://cn.rx.js.org/

关于异步编程方法的讲解,可以参考 Javascript异步编程的4种方法


目前常见的异步编程的几种方法:


  1. 回调函数
  2. 事件监听/发布订阅
  3. Promise
  4. Rxjs


本次测试需要新建一个 home2 组件,和 storage 服务,异步编程方法封装在 storage 服务中,供组件调用。


首先我们定义一个同步方法,来测试其效果。


1、storage.service.ts


getData() {
    // console.log('this is service data');
    return 'this is service data';
  }
复制代码


2、home2.component.ts


import {StorageService} from '../../services/storage.service';
  constructor(public storage: StorageService) {
  }
  /*//1、同步方法*/
  getData() {
    console.log(this.storage.getData());
  }
复制代码


3、页面测试


1.jpg


从结果可以看出,每点击一下按钮,同步方法就会立刻获取到数据。但是在实际生产中,同步操作容易造成堵塞问题,异步操作的出现很好的解决该问题。


回调函数


这是异步编程最基本的方法。


1、storage.service.ts


// 一秒后获取数据
  getCallbackData(cb) {
    setTimeout(() => {
      // tslint:disable-next-line:prefer-const
      let username = 'hresh';
      cb(username);
    }, 1000);
  }
复制代码


2、home2.component.ts


import {StorageService} from '../../services/storage.service';
  constructor(public storage: StorageService) {
  }
  getCallbackData() {
    /*2、通过Callback获取异步数据*/
    this.storage.getCallbackData((data) => {
      console.log(data);
    });//a操作
    console.log('延时获取数据');//b操作
  }
复制代码


3、页面测试


1.jpg


从页面结果来看,a操作不会阻塞程序运行,会被推迟执行,不会影响b操作的执行。

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。


事件监听


另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。


演示代码如下:


import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';
@Component({
  selector: 'app-home2',
  templateUrl: '
      <h2>事件监听</h2>
      <input type="button" value="点击" id="btn">
      <input type="button" value="移除" id="del">
    '
})
export class Home2Component implements OnInit {
  fn1() {
    alert('first');
  }
  fn1() {
    alert('first');
  }
  fn2() {
    alert('second');
  }
  ngOnInit(): void {
    $('h2').css('color', 'blue');
    let $body = $('body');
    $body.delegate('#btn', 'click', this.fn1);
    $body.delegate('#btn', 'click', this.fn2);
    $('#del').on('done', () => alert('解除事件绑定'));
    setTimeout(() => {
      $('#del').trigger('done');
    }, 2000);
  }
}
复制代码


页面测试效果:


2.jpg


#btn 标签可以绑定多个事件,$('#del').trigger('done')表示页面初始化后,2s 之后会触发 done 事件,从而执行 alert 事件。


这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。


Promise


Promise 本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。 什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的才做,例如网络请求、读取本地文件等。


它的思想是,每一个异步任务返回一个 Promise 对象,该对象有一个 then 方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:


f1().then(f2);
复制代码


在 Angular 项目中可以使用如下测试案例:


1、storage.service.ts


getPromiseData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // tslint:disable-next-line:prefer-const
      let username = 'hresh----Promise';
      resolve(username);
    }, 2000);
  });
}
复制代码


2、home2.component.ts


import {StorageService} from '../../services/storage.service';
  constructor(public storage: StorageService) {
  }
  getPromiseData(){
    /*3、通过Promise获取异步数据*/
    let promiseObj = this.storage.getPromiseData();
    promiseObj.then((data) => {
      console.log(data);
    });
  }
复制代码


3、页面测试


1.jpg


另外 Promise 的 then 方法返回的是一个新的 Promise 实例,因此 then 可用链式调用。比如,指定多个回调函数:


f1().then(f2).then(f3);
复制代码


再比如,指定发生错误时的回调函数:


f1().then(f2).fail(f3);
复制代码


而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。

Rxjs


Rxjs 处理异步:


1、storage.service.ts


import { Observable } from 'rxjs';
getRxjsData() {
  return new Observable((observer) => {
    setTimeout(() => {
      let uname = 'hresh----Rxjs';
      observer.next(uname);
    }, 3000);
  });
}
复制代码


2、home2.component.ts


import {StorageService} from '../../services/storage.service';
  constructor(public storage: StorageService) {
  }
  getRxjsData(){
    /*4、通过Rxjs获取异步数据*/
    let observer = this.storage.getRxjsData();
    let oData = observer.subscribe((data) => {
      console.log(data);
    });
  }
复制代码


页面测试效果同 Promise 一样。从上面列子可以看到 RxJS 和 Promise 的基本用法非常类似, 除了一些关键词不同。 Promise 里面用的是 then() 和 resolve(),而 RxJS 里面用的是 next() 和 subscribe()。


其实Rxjs相比Promise 要强大很多。比如 Rxjs 中可以中途撤回、Rxjs 可以发射多个值、Rxjs 提供了多种工具函数等等。


Rxjs 可以通过 unsubscribe() 可以撤回 subscribe 的动作。


我们修改 home2.component.ts 文件内容如下:


import {StorageService} from '../../services/storage.service';
  constructor(public storage: StorageService) {
  }
  getRxjsData(){
    /*4、通过Rxjs获取异步数据*/
    let observer = this.storage.getRxjsData();
    let oData = observer.subscribe((data) => {
      console.log(data);
    });
      /*5、Rxjs允许取消订阅操作*/
    setTimeout(() => {
      oData.unsubscribe();
    }, 2000);
  }
复制代码


数据交互(Get,Post,jsonp)


Angular5.x 以后 Get、Post 和 jsonp 通过  HttpClientModule 模块来和服务器进行数据交互。


Get获取数据


1、 在 app.module.ts 中引入 HttpClientModule


import {HttpClientModule} from '@angular/common/http';
imports: [
    BrowserModule,
    HttpClientModule,
    HttpClientJsonpModule
]
复制代码


2、html 文件内容:


<p>new3 works!</p>
<br>
<hr>
<br>
<button (click)="getData()">get请求数据</button>
<br>
<hr>
<br>
<ul>
  <li *ngFor="let item of dataList">{{item.name}} --- {{item.age}}</li>
</ul>
<br>
复制代码


3、new3.component.ts 文件


import {Component, OnInit} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Component({
  selector: 'app-new3',
  templateUrl: './new3.component.html',
  styleUrls: ['./new3.component.css']
})
export class New3Component implements OnInit {
  dataList: any[] = [];
  constructor(public client: HttpClient) {
  }
  ngOnInit(): void {
  }
  getData() {
    // var api = 'http://a.itying.com/api/productlist';
    var api = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
    this.client.get(api).subscribe((data: any) => {
      console.log(data);
      this.dataList = data.members;
    });
  }
}
复制代码


4、网页运行效果如下:


2.jpg


Post获取数据


在 SpringMVC 项目构建后台服务方法,一个是用 RequestBody 接受参数,另一个是用 RequestParam 接受参数。


@RestController
@CrossOrigin(origins = "http://localhost:4200")
public class EncodingController {
    @RequestMapping(value = "/testPostPara2")
    public Map testPostPara2(@RequestParam String uname,@RequestParam int age){
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("name",uname);
        map.put("age",age);
        return map;
    }
    @RequestMapping("/testPostBody")
    public Map testPostBody(@RequestBody Map<String,Object> objectMap){
        System.out.println(objectMap.toString());
        return objectMap;
    }
}
复制代码


出于安全原因,浏览器禁止 Ajax 调用驻留在当前原点之外的资源。例如,当你在一个标签中检查你的银行账户时,你可以在另一个选项卡上拥有 EVILL 网站。来自 EVILL 的脚本不能够对你的银行 API 做出 Ajax 请求(从你的帐户中取出钱!)使用您的凭据。 跨源资源共享(CORS)是由大多数浏览器实现的W3C规范,允许您灵活地指定什么样的跨域请求被授权,而不是使用一些不太安全和不太强大的策略,如IFRAME或JSONP。


关于跨域的更多内容可以参考注解@CrossOrigin解决跨域问题


注意上述方法都返回的是 Map 类型,不需要转换为 String 类型返回。但是如果直接访问 http://localhost:8080/testPostPara2?uname=hresh22&age=24 是会报错的,必须转换为 String 类型。


1、同样需要在 ap.module.ts 中引入 HttpClientModule  模块并注入。

2、html


<br>
<button (click)="doPost2()">post提交数据:body中传参</button>
<br>
<hr>
<br>
<button (click)="doPost()">post提交数据:url后携带参数</button>
复制代码


3、new3.component.ts 文件


import {Component, OnInit} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Component({
  selector: 'app-new3',
  templateUrl: './new3.component.html',
  styleUrls: ['./new3.component.css']
})
export class New3Component implements OnInit {
  dataList: any[] = [];
  constructor(public client: HttpClient) {
  }
  ngOnInit(): void {
  }
  doPost() {
    const header = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };
    let url = 'http://localhost:8080/testPostPara2?uname=hresh22&age=24';
    this.client.post(url, {}, header).subscribe((response: any) => {
      console.log(response);
    });
  }
  doPost2() {
    const header = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };
    let url = 'http://localhost:8080/testPostBody';
    this.client.post(url, { 'uname': 'hresh', 'age': 24 }, header).subscribe((response: any) => {
      console.log(response);
    });
  }
}
复制代码


4、页面测试


需要先启动 web 项目,然后再启动 Angular 项目,点击页面上的按钮,查看效果。


1.jpg


jsonp获取数据


同 Get 请求获取数据一样,然后主要是添加 html 文件和 ts 中的方法。


1、 在 app.module.ts 中引入 HttpClientJsonpModule


import {HttpClientJsonpModule} from '@angular/common/http';
imports: [
    BrowserModule,
    HttpClientJsonpModule
]
复制代码


2、html


<button (click)="getJsonpData()">Jsonp获取数据</button>
复制代码


3、new3.component.ts 文件


getJsonpData() {
    var api = 'http://a.itying.com/api/productlist';
    this.client.jsonp(api, 'callback').subscribe((data) => {
      console.log(data);
    })
  }
复制代码


4、页面测试


2.jpg


第三方模块axios获取数据


1、安装 axios


npm install axios 
复制代码


2、配置服务文件 httpservice.service.ts


import {Injectable} from '@angular/core';
import axios from 'axios';
import {Observable} from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class HttpserviceService {
  constructor() {
  }
  //可以返回Promise对象,也可以使用Rxjs,根据个人习惯
  axiosGet(api) {
    return new Promise((resolve, reject) => {
      axios.get(api).then(function(res) {
        resolve(res);
      });
    });
  }
  axiosRxjs(api) {
    return new Observable(function(observer) {
      axios.get(api).then(function(res) {
        observer.next(res);
      });
    });
  }
}
复制代码


3、html 文件


<button (click)="getAxiosData()">Axios获取数据方式一</button>
<hr>
<br>
<button (click)="getAxiosData2()">Axios获取数据方式二</button>
复制代码


4、在用到的地方引入 httpservice 并在构造函数声明


import { HttpserviceService } from '../../services/httpservice.service';
  constructor(public client: HttpClient, public httpservice: HttpserviceService) {
  }
  //通过第三方模块获取服务器数据
  getAxiosData() {
    var api = 'http://a.itying.com/api/productlist';
    let axiosObj = this.httpservice.axiosGet(api);
    axiosObj.then((data) => {
      console.log(data);
    })
  }
  //通过Rxjs获取
  getAxiosData2() {
    var api = 'http://a.itying.com/api/productlist';
    let axiosObj = this.httpservice.axiosRxjs(api);
    axiosObj.subscribe(function (data) {
      console.log(data);
    })
  }
复制代码


5、页面测试


1.jpg


目录
相关文章
|
设计模式 JavaScript 前端开发
学习Angular的编程之旅
学习Angular的编程之旅
|
前端开发 JavaScript API
Angular与Rxjs学习
Angular与Rxjs学习
155 0
Angular与Rxjs学习
|
前端开发 JavaScript 网络架构
Angular基础知识学习(三)
Angular基础知识学习(三)
152 0
Angular基础知识学习(三)
|
缓存 前端开发 JavaScript
Javascript学习-angular开发环境搭建及新建项目并运行
Javascript学习-angular开发环境搭建及新建项目并运行
114 0
Javascript学习-angular开发环境搭建及新建项目并运行
|
JavaScript 开发者
Angular基础知识学习(二)上
Angular基础知识学习(二)上
128 0
Angular基础知识学习(二)上
|
JavaScript
Angular基础知识学习(一)下
Angular基础知识学习(一)下
180 0
Angular基础知识学习(一)下
|
前端开发 JavaScript 安全
Angular基础知识学习(一)上
Angular基础知识学习(一)上
173 0
Angular基础知识学习(一)上
|
3月前
|
API 开发者 UED
PrimeFaces:JSF的魔法衣橱,解锁UI设计的无限可能!
【8月更文挑战第31天】本文介绍如何结合 JSF(JavaServer Faces)和 PrimeFaces 构建美观且功能强大的现代用户界面。PrimeFaces 提供丰富的 UI 组件库,包括按钮、输入框、数据网格等,支持现代 Web 标准,简化界面开发。文章通过具体示例展示如何使用 `&lt;p:inputText&gt;` 和 `&lt;p:calendar&gt;` 等组件创建用户表单,并用 `&lt;p:dataTable&gt;` 展示数据集合,提升 JSF 应用的易用性和开发效率。
61 0
|
3月前
|
开发者 安全 SQL
JSF安全卫士:打造铜墙铁壁,抵御Web攻击的钢铁防线!
【8月更文挑战第31天】在构建Web应用时,安全性至关重要。JavaServer Faces (JSF)作为流行的Java Web框架,需防范如XSS、CSRF及SQL注入等攻击。本文详细介绍了如何在JSF应用中实施安全措施,包括严格验证用户输入、使用安全编码实践、实施内容安全策略(CSP)及使用CSRF tokens等。通过示例代码和最佳实践,帮助开发者构建更安全的应用,保护用户数据和系统资源。
54 0
|
3月前
|
开发者 C# C++
揭秘:如何轻松驾驭Uno Platform,用C#和XAML打造跨平台神器——一步步打造你的高性能WebAssembly应用!
【8月更文挑战第31天】Uno Platform 是一个跨平台应用程序框架,支持使用 C# 和 XAML 创建多平台应用,包括 Web。通过编译为 WebAssembly,Uno Platform 可实现在 Web 上运行高性能、接近原生体验的应用。本文介绍如何构建高效的 WebAssembly 应用:首先确保安装最新版本的 Visual Studio 或 VS Code 并配置 Uno Platform 开发环境;接着创建新的 Uno Platform 项目;然后通过安装工具链并使用 Uno WebAssembly CLI 编译应用;最后添加示例代码并测试应用。
108 0