您的当前位置:首页正文

ANGULAR2使用培训

2023-09-01 来源:易榕旅网
Angular2使用培训

目录结构

关于angular的两个为什么ES6新特性

angular2八大核心构造

60分钟构造一个angular2应用——恒拓富豪榜ionic简介

关于angular2的两个为什么为什么angular2重写?

javascript框架跟类库一直是百花齐放的状态,特别是最近几年。回顾这几年,有些框架非常的引入注目,其中一个就是Angular。Angular最火的时间是2013年中到2014年末,但是在14年末的时候,官方突然宣布了一个重大消息,要完全重写Angular2.0。这个事情让很多想要使用Angular的人止步不前,也给人带来了很多的困惑,为什么Angular2.0要重写?

首先,性能。Angular这货刚创建出来的时候,并不是给开发人员用的。它是给那些需要快速创建持久化HTML表单的设计人员使用的一种工具。随着时间推移,它作了改变以适应各种场景,开发人员也用它建造更多、更复杂的应用程序。也正因如此,绑定与模板基础架构的性能问题凸显,问题根源在于原始设计,为了解决问题,需要新的策略。

第二,变化的web。这几年,web发生了很多变化,五六年前吧,没有jQuery这种类库的帮助,是基本不可能建立一个跨浏览器的网站的,但是现在浏览器的DOM实现

更加一致也更加快了,加上ES6规范的定稿,WebComponents即web应用组件化标准或者说概念的完善,这些变化统统要求Angular作出相应的变化以拥抱未来。第三,移动端。现在满大街都是智能手机和平板,虽说Angular1也可以用来构建移动应用,但是它并非为移动端而生,这里就产生了很多问题,包括提过的性能,它的路由的能力缺失,以及不能缓存预编译视图,甚至是过于普通的触摸支持,这些都需要根本的变更来修复。

第四,易用性。网上大把大把的开发者吐槽,Angularjs的学习曲线太他妈陡峭啦!甚至还有人非常直观的图表现了自己学习使用AngularJS的心态变化。

这跌宕起伏的心态,看着就糟心啊!这些原因逼迫着angular2进行重写。

为什么选择angular2?

可能大家都知道,无限极大平台2.0打算选用angular2+ionic2作为开发框架,为什么是angular2呢?

从前端的角度看,Vue有一万个好,Angular有一万种令人不满的地方,但企业领域的人偏爱集成解决方案,哪怕这个方案的语法是粗陋的,配置是繁琐的,连Java都用了,还怕这些?是的,angular2就像一台已经装配好的电脑,而react之流就像一个个零件,需要组装。而且angular2拥抱webcomponent,这跟用户想要做一个轻应用的需求不谋而合,在这点上angular2就狠狠甩了react十几条街,react根本不angular2支持对html的拓展。而且angular2更加稳定、可扩展和更加完善。再说了,还具有下面几个鲜明的特性

跨平台(渐进式web应用,原生,桌面)面向未来(以es6为基础加入了类型和注解。Es6能让angular有更出色的表现,让代码变得更加清洁,易读性更强)开发灵活(可以自由决定对开发语言的选择,ES6,typescript等)速度与性能(代码生成、统一,代码拆分)生产率(模板,angular命令行工具,各种ide)完整的开发故事(测试,动画,可访问性)ES6新特性1.let和const

1.let命令

let命令,用来声明变量。用法类似于var,但是所生命的变量,只在let命令所在的代

码块内有效。例子:

{leta=10;varb=1;}a//ReferenceError:aisnotdefined.b//12.let命令的特点

只在所在代码块内有效不存在变量提升,变量一定要在声明后使用,否则会报错暂时性死区(只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响)不允许重复声明暂时性死区例子:

if(true){//TDZ(暂时性死区)开始tmp='abc';//ReferenceErrorconsole.log(tmp);//ReferenceErrorlettmp;//TDZ(暂时性死区)结束console.log(tmp);//undefinedtmp=123;console.log(tmp);//123}3.let带来了什么

众所周知,ES5只有全局作用域和函数作用域,没有块级作用域,这导致了很多不合理的场景,一内层变量可能会覆盖外层变量,二用来计数的循环变量泄露为全局变量。而let实际上为javascript新增了块级作用域。4.const命令

const声明一个可读的常量。一旦声明,就必须立即初始化,不能留到以后赋值,且常量的值不能改变。与let命令相同(具有相同的特点),只在声明所在的块级作用域内有效。(对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址)

箭头函数

1.箭头函数的语法

ES6允许用“箭头”(=>)定义函数。箭头左边是参数,右边是函数的具体内容。例子:

varf=v=>v;//等同于varf=function(v){returnv;};如果箭头函数不需要参数或者需要多个参数,就使用一个圆括号代表参数部分。

varf=()=>5;//等同于varf=function(){return5};varsum=(num1,num2)=>num1+num2;//等同于varsum=function(num1,num2){returnnum1+num2;};如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。

varsum=(num1,num2)=>{returnnum1+num2;}由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。

vargetTempItem=id=>({id:id,name:\"Temp\"});2.箭头函数使用注意点

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象(尤其值得注意)。不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。不可以使用yield命令,因此箭头函数不能用作Generator函数。在es5中,this对象的指向是可变的,但是在箭头函数中,它是固定的。箭头函数this代码示例

箭头函数可以让this指向固定化,这种特性很有利于封装回调函数。

this指向的固定化,是因为箭头函数本身没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。箭头函数转化成ES5的代码如下:

//ES6functionfoo(){setTimeout(()=>{console.log('id:',this.id);},100);}//ES5functionfoo(){var_this=this;setTimeout(function(){console.log('id:',_this.id);},100);}由于箭头函数没有自己的this,所以我们就不能用call()、apply()、bind()这些方法去改变this的指向。

长期以来,JavaScript语言的this对象一直是一个令人头痛的问题,在对象方法中使用this,必须非常小心。箭头函数”绑定”this,很大程度上解决了这个困扰。

但是,箭头函数并不适用于所有场合,所以ES7提出了“函数绑定”(functionbind)运算符,用来取代call、apply、bind调用。虽然该语法还是ES7的一个提案,但是Babel转码器已经支持。

函数绑定运算符是并排的两个双冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

Promise

1.Promise的含义

Promise是一部编程的一种解决方案,比传统的解决方案——回调函数和事件更加合理更加强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一愕对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。Promise对象有以下两个特点:

对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任务其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英文意思是“承诺”,表示其他手段无法改变。一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只有这两种情况发送,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发送了,你再对Promise对象添加回调函数,也会立即得到这个结果。。这跟事件是完成不同的,事件的特点是,如果你错过了它,再去监听,是得不到结果的。有了Promise对象,就可以用同步操作的流程表达异步操作,避免了层次嵌套的回调函数。此外,Promise对象提供统一的接口,使控制异步操作更加容易。Promise的优点很明显,同样的,它的缺点也是很明显的:

无法取消Promise,一旦新建它就会立即执行,无法中途取消;如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;当处于Pending状态时,无法得知目前进展到哪一个阶段(比如,是刚刚开始还是即将完成)2.Promise基本用法

ES6规定,Promise对象是一个构造函数,用来生成Promise实例。下面代码创造了一个Promise实例。

varpromise=newPromise(function(resolve,reject){//...somecodeif(/*异步操作成功*/){resolve(value);}else{reject(error);}});Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending

变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

promise.then(function(value){//success},function(error){//failure});then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

下面看一个Promise对象的简单例子

代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。Promise实例的状态变为Resolved,过了指定的时间(ms参数)以后,就会触发then方法绑定的回调函数。Promise新建后立即执行,所以首先输出的是“Promise”。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行。

class

1.class语法

javascript语言的传统方法是通过构造函数,定义并生成新对象。就像下面这个例子:

functionPoint(x,y){this.x=x;this.y=y;}Point.prototype.toString=function(){return'('+this.x+','+this.y+')';};varp=newPoint(1,2);这种写法跟传统的面向对象语言(如c++,java)差异很大,这让很多有传统面向对象语言背景的程序员感到非常的困惑。

因此,ES6提供了更接近传统语言的写法,引入了Class(类)的概念,作为对象的模板。通过class关键字,可以定义类。但是,从根本上说,ES6的class可以看作只是一饿语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面point的例子用ES6的“类”进行改写,就是下面这样。

//定义类classPoint{constructor(x,y){this.x=x;this.y=y;}toString(){return'('+this.x+','+this.y+')';}}它定义了一个“类”,里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数Point,对应ES6的Point类的构造方法。Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。ES6的类,完全可以看作构造函数的另一种写法。下面,我们通过表格来看一下ES6的类跟ES5构造函数之间的异同点。2.class语法与ES5行为对比ES6Class使用new命令产生新的示例对象ES5构造函数是是具有prototype属性prototype对象的constructor属性,直接指向“类”的本身类的内部所有定义的方法,都是不可枚举的不使用new是没法调用是是是是是是否否Module

1.ES6模块产生从必然性及其设计思想

Module功能是为了解决模块化问题而提出的。历史上,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如Ruby的require、Python的import,甚至就连CSS都有@import,但是JavaScript任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。为此,开发者社区制定了一些模块加载方案,我们耳熟能详的就有CommonJS和AMD两种。前者用于服务器,后者用于浏览器。ES6在语言规格的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。2.严格模式

ES6的模块自动采用严格模式,不管你有没有在模块头部加上\"usestrict\";。严格模式主要有以下限制。

变量必须声明后再使用函数的参数不能有同名属性,否则报错不能使用with语句不能对只读属性赋值,否则报错不能使用前缀0表示八进制数,否则报错不能删除不可删除的属性,否则报错不能删除变量deleteprop,会报错,只能删除属性deleteglobal[prop]eval不会在它的外层作用域引入变量eval和arguments不能被重新赋值arguments不会自动反映函数参数的变化不能使用arguments.callee不能使用arguments.caller禁止this指向全局对象不能使用fn.caller和fn.arguments获取函数调用的堆栈增加了保留字(比如protected、static和interface)3.export命令

模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个JS文件,里面使用export命令输出变量。export输出变量的写法有两种,

//写法一exportvarm=1;//写法二varm=1;export{m};//写法三重命名varn=1;export{nasm};//输出多个变量的推荐写法//profile.jsvarfirstName='Michael';varlastName='Jackson';varyear=1958;export{firstName,lastName,year};如果需要输出多个变量,我们推荐的写法是,在export命令后面,使用大括号制定要输出的一组变量,这种写法可以让我们一眼就看清楚输出了哪些变量。export命令除了输出变量,还可以输出函数或类(class)。

exportfunctionmultiply(x,y){returnx*y;};exportclassPoint{constructor(x,y){this.x=x;this.y=y;}toString(){return'('+this.x+','+this.y+')';}}4.import命令

使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。语法如下:

//main.jsimport{firstName,lastName,year}from'./profile';functionsetName(element){element.textContent=firstName+''+lastName;}上面代码的import命令,就用于加载profile.js文件,并从中输入变量。import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。同样的,import命令可以使用as关键字对输入的变量重新命名。

import{lastNameassurname}from'./profile';需要注意的是,import命令具有提升效果,会提升到整个模块的头部,首先执行。因此,下面这段代码不会报错。

foo();import{foo}from'my_module';angular2八大核心Angular2是一个用HTML和Javascript或者一个编译成javascript的语言(如Typescript或者Dart),来构建客户端应用的框架。

这个框架包括一系列与之紧密合作的库,有些是核心库,有些的可选库。

我们在angular里面,是这样编写程序的,用directive(即指令,带angular扩展语法的html)来编写模板,用组件类管理这些模板,用服务添加应用逻辑,用根组件完成angular启动。

Angular在浏览器中接管、展现应用的内容,并根据我们提供的操作指令响应用户的交互。

首先,我们先从宏观上了解angular架构,如下图:

架构图中展现了angular应用中的8个主要构造块:

模块(Modules)组件(Components)模板(Templates)元数据(Metadata)数据绑定(DataBinding)指令(Directives)服务(Services)依赖注入(DependencyInjection)模块

Angular应用是模块化的。应用程序通常都是由很多模块组装而成的。虽说完全可以使用ES5来开发Angular2应用,但是这并不是官方推荐的做法,官方强烈推荐使用模块化设计,推荐使用Typescript,Typescript对ES6的模块语法支持性很好。官网目前也只有typescript的教程。

大多数Angular应用都有一个AppComponent。它通常位于一个名叫app.component.ts的文件中,里面有这样一条export语句,

exportclassAppComponent{}它告诉Typescript:这是一个模块,其中AppComponent类是公开的,可以被应用程序中的其他模块访问。当需要引用AppComponent时,这样导入:

import{AppComponent}from'./app.component';这跟我们之前介绍的ES6的模块语法完全一样。(模块就暂时这样,后续可能还要增加一些内容)关键点:

Angular应用是由模块组成的。模块导出一些东西——类,函数,值,供其它模块导入。首选的写法是把应用写成一组模块,每个模块只导出一样东西。组件

组件控制屏幕中巴掌大的那么一小块地方,这块地方被称之为视图。我们在类中定义组件的应用逻辑(它被用来为视图提供支持)。组件通过一些由属性和方法组成的API与视图交互。

比如,在HeroListComponent组件中,可能有一个heroes属性,它返回一个英雄的数组,而这些数据是从服务中取得的。它可能还有一个selectHero()方法,当用户从列表中点击一个英雄时,用它来设置selectedHero属性。这个组件可能是像这样的一个类:

exportclassHeroListComponentimplementsOnInit{heroes:Hero[];selectedHero:Hero;constructor(privateservice:HeroService){}ngOnInit(){this.heroes=this.service.getHeroes();}selectHero(hero:Hero){this.selectedHero=hero;}}但是如果只是这样,这就仅仅是一个类,而不能称之为组件,它现在是万事俱备只欠东风,下面我们讲元数据的时候会说明这个问题。

当用户在这个应用中“移动”时,Angular会创建、更新和销毁组件。开发人员可以通过生命周期钩子在组件生命周期的各个时间点上插入自己的操作,比如上面声明的ngOnInit()。

模板

我们通过组件的自带的模板来定义视图。模板以HTML形式存在,用来告诉Angular如何渲染组件(视图)。说白了,模板就是一个使用了Angular模板语法以及自定义元素标签的html。看起来可能想这样:

HeroList

Pickaherofromthelist

元数据

元数据告诉Angular如何处理一个类。我们刚刚说了,HeroListComponent只是一个类,在我们告诉Angular这是一个组件之前,它只是一个类。那么,我们如何把这个信息传递给angular呢?答案就是元数据,只要把元数据附加到这个类,angular就知道这个类是个组件。

在Typescript中,我们用装饰器(decorator)来附加元数据。想这样:

@Component({selector:'hero-list',templateUrl:'app/hero-list.component.html',directives:[HeroDetailComponent],providers:{/*...*/}[HeroService]})exportclassHeroListComponentimplementsOnInit装饰器就是函数,它们通常还带有配置参数。@Component装饰器能接受一个配置对象,Angular会基于这些信息创建和展示组件及其视图。下面,我们看看@Component中的一些配置项:

selector——一个css选择器,通常是一个自定义标签,它告诉angular在父级html中寻找这个标签,然后创建该组件,并插入此标签中。templateUrl——组件模板的地址。directives——一个数组,包含此模板需要依赖的组件或者指令。providers——一个数组,包含主键所依赖的服务所需要的依赖注入提供商。styleUrls——一个数组,Angular读取@Component里面的元数据设置,并由此知道如何去“做正确的事”。从这个意义上说,元数据相当于一个指导者,指导Angular的行为。除了@Component,@Injectable、@Input和@Output等都是一些最常用的装饰器。

数据绑定

如果没有框架,我们就得自己把数据值推送到HTML控件中,并把用户的反馈转换成动作和值更新。如果让我们自己手工写代码来实现这种推逻辑,这听起来就是个噩梦。

angular支持数据绑定,这就把我们从那种噩梦中解放了出来。数据绑定是一种让模板的各部分与组件的各部分相互合作的机制。我们往模板HTML中添加绑定标记,来告诉Angular如何连接两者。

数据绑定的语法有四种形式。每种形式都有一个方向——从DOM来、到DOM去、双向,如下图:

例子:

  • {{hero.name}}
  • 在双向绑定中,数据属性的值会从具有属性绑定的组件传到输入框。通过事件绑定,用户的修改被传回到组件,把属性值设置为最新的值。

    Angular在每个javascript事件周期中一次性处理所有的数据绑定,它会从组件树的根部开始,自顶向下处理各个叶节点。

    数据绑定在模板与对应组件的交互中,以及父组件与子组件的通讯中都扮演着重要的角色。

    指令

    Angular模板是动态的。当Angular渲染它们的时候,它会根据指令提供的操作指南对dom进行修改。

    指令是一个带有“指令元数据”的类。在Typescript中,要通过@Directive装饰器把元数据附件到类上。

    指令有三种类型,组件,结构型指令和属性型指令。

    组件——组件是一个带模板的指令,而且@Component装饰器实际上就是一个@Directive装饰器,只是拓展了一些面向模板的属性。结构型指令——通过在dom中添加、移除和替换元素来修改布局。属性型指令——修改一个现有元素的外观或行为,它们在模板中看起来就像标准的html属性,名字也由此而来。例子:*ngFor告诉Angular为heroes列表中的每个英雄生成一个

    标签。

    *ngIf表示只有在选择的英雄存在时,才会包含HeroDetail组件。

    ngModel指令实现了双向数据绑定。它修改了现有元素(一般是input)的行为:它设置了显示属性值,并对change事件做出相应回应。

    服务

    服务分为很多种,包括:值、函数,以及应用所需的特性。几乎任何东西都可以是

    一个服务。电信的服务是一个类,具有专注的。良好定义的用途。它应该做一件具体的事情,把它做好。

    Angular本身对于服务也没有什么定义。即使如此,服务仍旧是任何Angular应用的基础。组件就是最大的服务消费者。

    我们更倾向于让组件保持精简。组件不需要从服务器获得数据、不需要验证输入,也不需要直接往控制台写日志。它们把这些任务委托给了服务。

    组件的任务就是提供用户体验,仅此而已。它介于视图(由模板渲染)和应用逻辑(通常包括模型(model)的观念)之间。设计良好的组件为数据绑定提供属性和方法,把那些其他对它们不重要的事情都委托给服务。

    

    依赖注入

    “依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多

    数依赖都是服务。Angular也是用依赖注入提供我们需要的组件以及这些组件所需的服务。

    Angular能通过查看构造函数(constructor)的参数类型,来得知组件需要哪些服务。当Angular创建组件时,会首先为组件所需的服务着一个注入器(Injector)。注入器是一个维护服务实例的容器,存放着以前创建的实例。如果容器中还没有所请求的服务实例,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给Angular。当所有的服务都被解析完并返回时,Angular会以这些服务为参数去调用组件的构造函数。这就是我们所说的依赖注入。

    必须在要求注入一个服务之前,注册一个服务的提供商Provider到注入器。提供商可以创建并返回服务,通常返回的就是这个“服务类”本身。

    可以在应用程序的组件树中的任何级别上注册提供商。当需要一个服务的同一个实例在任何地方都是可用时,我们通常在应用引导程序中注册它。

    bootstrap(AppComponent,[BackendService,HeroService,Logger]);或者,也可以在@Component元数据中的providers属性中把它注册在组件层。

    需要记住的关于依赖注入的要点是:

    

    依赖注入渗透在整个Angular框架中,并且被到处使用。注入器是本机制的核心。它负责维护一个容器,用于存放它创建过的服务实例,并且能使用提供商创建一个新的服务实例。提供商是一个用于粗昂就服务的“配方”。把提供商注册到注入器。60分钟构建一个angular2应用五分钟快速起步

    环境准备:安装Node.js步骤1:创建本应用的项目文件夹,并且定义包的依赖以及特别的项目设置。步骤2:创建本应用的Angular根组件步骤3:添加main.ts,用来告诉Angular哪个是根组件。步骤4:添加index.html,本应用的宿主界面。-步骤5:构建并运行本应用环境准备:Node.js

    安装node和npm,在终端窗口运行node-v和npm-v,确认我们的node版本为v5.x.x,npm版本为3.x.x。老版本会出错。创建并配置项目1.创建项目文件夹2.添加包定义和配置文件

    在项目目录下添加下来包定义和配置文件:

    package.json列出了应用的依赖,并定义了一些有用的脚本。参见npm包配置了解详情。

    tsconfig.json是typescript的编译器配置文件。参见typescript配置了解详情。typings.json制定typescript定义文件。参见typescript定义文件了解详情。systemjs.config.js是SystemJS的配置文件。参见SystemJS配置文件了解详情。以下是package.json的文件详情

    {\"name\":\"angular2-quickstart\",\"version\":\"1.0.0\",\"scripts\":{\"start\":\"tsc&&concurrently\\\"npmruntsc:w\\\"\\\"npmrunlite\\\"\",\"lite\":\"lite-server\",\"postinstall\":\"typingsinstall\",\"tsc\":\"tsc\",\"tsc:w\":\"tsc-w\",\"typings\":\"typings\"},\"license\":\"ISC\",\"dependencies\":{\"@angular/common\":\"2.0.0-rc.4\",\"@angular/compiler\":\"2.0.0-rc.4\",\"@angular/core\":\"2.0.0-rc.4\",\"@angular/forms\":\"0.2.0\",\"@angular/http\":\"2.0.0-rc.4\",\"@angular/platform-browser\":\"2.0.0-rc.4\",\"@angular/platform-browser-dynamic\":\"2.0.0-rc.4\",\"@angular/router\":\"3.0.0-beta.1\",\"@angular/router-deprecated\":\"2.0.0-rc.2\",\"@angular/upgrade\":\"2.0.0-rc.4\",\"systemjs\":\"0.19.27\",\"core-js\":\"^2.4.0\",\"reflect-metadata\":\"^0.1.3\",\"rxjs\":\"5.0.0-beta.6\",\"zone.js\":\"^0.6.12\",\"angular2-in-memory-web-api\":\"0.0.14\",\"bootstrap\":\"^3.3.6\"},\"devDependencies\":{\"concurrently\":\"^2.0.0\",\"lite-server\":\"^2.2.0\",\"typescript\":\"^1.8.10\",\"typings\":\"^1.0.4\"}}我们可以看到,package.json把这些包分成了两组:dependecies和devDependencies。

    列在dependencies下的这些包是运行本应用的基础,而devDependencies下的只在开发此应用时才用得到。dependencies下有三类包:

    特性——特性包为我们的应用程序提供了框架和工具方面的能力。填充——填充弥合了不同浏览器上的javascript实现方面的差异。其他——其他库对本应用提供支持,比如bootstrap包提供了html中的小部件和样式。特性包

    @angular/core-框架中关键的运行期部件,每一个应用都需要它。包括所有的元数据装饰器:Component、Directive,依赖注入系统,以及组件生命周期钩子。

    @angular/common-常用的那些由Angular开发组提供的服务、管道和指令。@angular/compiler-Angular的模板编译器。它会理解模板,并且把模板转化成代码,以供应用程序运行和渲染。3,安装依赖包

    npminstall这里需要注意的是,如果在npminstall之后,typings目录没有出现,就需要我们手动安装。

    npmrumtypingsinstall创建我们的第一个Angular组件

    在项目的根目录下创建一个app子目录,用于保存引用程序,并且添加一个超级简单的Angualr组件。

    1.创建组件文件app/app.components.ts(在新建的子目录中),内容如下:

    import{Component}from'@angular/core';@Component({selector:'my-app',template:'

    MyFirstAngular2App

    '})exportclassAppComponent{}这里我们来解释一下,每个Angular应用都至少有一个根组件,习惯上命名为AppComonent,它是放置用户界面的容器。组件通过它所关联的模板,控制屏幕的一部分——这就是视图。我们现在写的这个组件虽然非常简单,但是它也具备了将来写的组件的基本结构。

    一个或多个import语句来引入所需的文件。一个@Component装饰器,指导Angular该使用哪个模板,和怎样创建这个组件。一个组件类,通过它的模板控制一个试图的外观和行为,这也是我们通常编写业务逻辑的地方。这里,我们引入了Anuglar2核心库,一遍组件代码访问@Component装饰器。我们在@Component装饰器当中,有一个元数据对象,其中selector字段指定了标签作为放置组件的html元素,Angular会创建和显示AppComponent组件的一个实例,然后放在宿主页面的一个my-app元素中。template字段制定了该组件的模板。

    这个组件实现的是很简单的功能,在my-app元素中显示一行标题。添加main.ts

    现在,我们需要做点什么来让Angular加载这个根组件。添加一个新文件app/main.ts,内容如下:

    import{bootstrap}from'@angular/platform-browser-dynamic';import{AppComponent}from'./app.component';bootstrap(AppComponent);我们引入了Angular的浏览器bootstrap(引导)函数和应用的根组件AppComponent,接着调用引导函数(传入根组件),来启动本应用。

    添加index.html

    在目录下创建一个index.html文件,并粘贴一下内容:

    Angular2QuickStartLoading...index.html是存放应用的宿主页面。这里有三个值得注意的地方:

    javascript库配置systemjs,以便引入和运行刚才写的main文件中的标签是应用程序赖以生存的地方。1.库

    首先引入es6-shim,它会给全局对象window打上补丁,使其支持ES2015(ES6)的必备特性。

    然后是

    Angular2的

    polyfills,以及

    zone.js和

    reflect-metadata。然后是用于模块加载的SystemJS库。2.SystemJs

    我们在一开始构建项目的时候就在根目录里添加了systemjs.config.js文件,这个配置文件首先创建了一个映射表,来告诉SystemJS当相应引入某些模块的时候,该去哪里找。然后把自己的所有包注册到了SystemJS中:项目的所有外部依赖,以及自己的应用包app。app包告诉SystemJS,当有人请求app/目录下的某个模块时,它该怎么做。

    我们的应用程序在运行前会执行从TypeScript到javascript的转译,所以package配置项告诉SystemJS使用js扩展名,即加载一个javas文件。

    System.import调用告诉SystemJS引入main.js文件。main.js是让Angualr启动应用的地方,还会把启动过程中的错误捕获并记录到控制台中。

    添加一些样式

    我们可以添加一些样式,让应用更加漂亮。构建并运行应用

    在终端窗口输入以下命令:

    npmstart这个命令运行两个并行的node进程

    typescript编译器,运行在监视模式一个名叫lite-server的静态服务器,它把index.html加载到浏览器中,当应用的文件发送变化时,它会自动刷新浏览器恒拓富豪榜应用构建

    我们伟大的革命领袖——毛主席曾经说过“实践是检验真理的唯一标准”。咱们学习编程语言也一样,光有理论不行,还得实操。下面,我们就用Anular来构建一个简单的应用。在开始构建应用之前,先给大家讲个小故事,大家注意听,这个故事很重要。有一天,冬哥跑过来跟我说,文青,听说你最近在学习angular2,文青,这样,你呢,用angular2整一个应用,叫恒拓富豪榜。这个应用简单一点丑一点都没有关系,你就当练练手,但是,有几个需求你是必须满足的,第一应用首页,应用首页显示恒拓四大富豪,点击每个富豪都可以跳转到富豪详情页,首页上还有两个按钮,点击分别是“四大富豪”和“富豪排行榜”,点击可以在四大富豪和富豪排行榜两个页面进行跳转;第二,富豪排行榜页面显示恒拓前15名富豪,点击每个富豪都可以跳转到富豪详情页面;第三,富豪详情页面显示富豪的排名,姓名(可编辑),财富,页面有个标题叫xxx的富豪详情,xxx根据编辑的姓名变化而变化,有个返回按钮可以返回到应用首页。第四,每个页面都必须具有首页的标题和“四大富豪”和“富豪排行榜”两个按钮,换句话说就是页面跳转的时候这部分不变,其他部分变。需求就这些,事成之后给你两个月A绩效,外加两千块奖金,需要什么资料,你就跟我说,你就一句话,干不干?好,故事讲完了。以上故事纯属虚构,如有雷同,纯属巧合。

    弟兄们,现在让我们来假设一下,假设我们接下了冬哥这个需求,我们怎么做呢?基于最简单应用出发。

    显示我们恒拓的富豪

    现在,我们为AppComponent添加两个属性;title属性表示应用的名字,fuhao属性表示一个名叫“马越”的富豪。

    exportclassAppComponent{title='恒拓富豪榜';fuhao='马越';}现在,我们需要为这些新属性建立数据绑定,以更新@Component装饰器中指定的模板

    template:'

    {{title}}

    {{fuhao}}的富豪详情!

    '保存后,浏览器自动刷新,并显示我们的标题和富豪的名字。

    根据我们的需求,富豪除了名字,还有排名和财富。所以我们需要把fuhao从一个字符串字面量换成一个类。我们创建一个Fuhao类,它具有id,name和asset属性。把下面这段代码放到app.component.ts,跟在import语句后面。

    exportclassFuhao{id:number;name:string;asset:string;}现在我们已经有了一个Fuhao类,接着我们就要把组件fuhao属性的类型转换成Fuhao。然后以1为排名、“马越”为名字,“1982亿元”为财富,对它进行初始化。

    fuhao:Fuhao={id:1,name:'马越',asset:'1982亿元'}接着,我们得更新模板中的绑定表达式,并添加显示更多的富豪属性。

    template:'

    {{title}}

    {{fuhao.name}}的富豪详情!

    {{fuhao.id}}
    '
    {{fuhao.asset}}
    '我们的模板字符串写成这样实在太恶心了,不仅可读性差,丑,还容易出现拼写错误。幸运的是,我们可以借助ES6和typescript提供的多行模板字符串来使我们的模板字符串保持清爽,只要把模板的双引号改成反引号,就可以像我们平时写html页面那样写模板了。

    template:`

    {{title}}

    {{fuhao.name}}的富豪详情!

    {{fuhao.id}}
    当没有selectedFuhao时,ngIf指令会从dom中移除表示富豪详情的这段html。

    我们顺带给富豪列表添加一个选择效果。

    [class.selected]=\"fuhao===selectedFuhao\"(click)=\"onSelect(fuhao)\">{{fuhao.id}}{{hero.name}}现在,我们的富豪列表和富豪详情位于同一个文件的同一个组件中,这个组件违反

    了单一职责原则。我们现在需要做的事情就是把它们拆分成不同的组件。

    首先,在app目录下添加一个名叫fuhao-detail.component.ts的文件,并且创建FuhaoDetailComponent。代码如下:

    import{Component,Input}from'@angular/core';@Component({selector:'my-fuhao-detail',})exportclassFuhaoDetailComponent{}再把富豪详情模板的内容从AppComponent中剪切出来,粘贴到

    FuhaoDetailComponent组件的template属性中。FuhaoDetailComponent组件将会有fuhao属性,将selectedFuhao替换成fuhao。最终结果如下:

    @Component({selector:'my-fuhao-detail',template:`

    {{fuhao.name}}的富豪详情!

    {{fuhao.id}}
    `,})

    添加fuhao属性

    fuhao:Fuhao;app.component.ts和app.FuhaoDetailComponent.ts里的组件都需要引用

    Fuhao类,因此,我们把app.component.ts中的Fuhao类转移到hero.ts中,再在app.component.ts和app.FuhaoDetailComponent.ts的顶部引入Fuhao类:

    import{Fuhao}from'./fuhao';接下来需要让AppComponent告诉FuhaoDetailComponent该显示哪个英雄。

    我们升级一下AppComponent的模板,把组件的selectedFuhao属性绑定到FuhaoDetailComponent组件的fuhao属性上。

    

    注意,在等号(=)左边方括号中的这个hero是属性绑定的目标。

    Angular希望我们把目标属性定义成组件的输入属性,否则,Angular会拒

    绝绑定,并且抛出一个错误。

    我们有几种方式把fuhao声明成输入属性。这里我们采用首选的方式:使用我们前面导入的@易荣泽装饰器,为fuhao属性加上注解。

    @Input()fuhao:Fuhao;

    接着在AppComponent中,导入FuhaoDetailComponent组件,

    import{FuhaoDetailComponent}from'./fuhao-detail.component';

    在刚刚移除富豪详情模板的地方,添加FuhaoDetailComponent组件的html标

    然而,此时,Angular还不认识标签,我们需要把它列在元数据的directives数组

    中。

    

    directives:[FuhaoDetailComponent]现在来盘点一下我们已经构建完成的部分。

    我们创建了一个可复用的组件我们学会了如何让一个组件接收输入我们学会了把父组件绑定到子组件我们学会了在directives中定义应用所需的指令接下来我们将要把数据访问逻辑抽取到一个独立的服务中,并在需要数据的组件之间共享。

    我们即将添加一个“四大富豪”来显示财富值最高四位富豪,这需要富豪的数据。目前,AppComponent显示的是我们自定义的一个mock富豪数据,为了让富豪数据可以共享给其他组件和视图,我们可以把提供富豪数据的任务重构为一个单独的服务。

    首先,从app.component.ts文件中剪切FUHAOS数组,并把它粘贴到app目录下一个名叫mock-fuhaos.ts的文件中。我们还要把import{Fuhao}...语句拷贝过来,因为我们的英雄数组用到了Fuhao类。

    import{Fuhao}from'./fuhao';exportconstFUHAOS:Fuhao[]=[{id:1,name:'马越',asset:'1982亿元'},{id:2,name:'杨冬',asset:'1500亿元'},{id:3,name:'付佳龙',asset:'1321亿元'},{id:4,name:'苏羊城',asset:'1221亿元'},{id:5,name:'唐友华',asset:'1300亿元'},{id:6,name:'陈健龙',asset:'1221亿元'},{id:7,name:'罗雅丹',asset:'1121亿元'},{id:8,name:'郑泰旋',asset:'1021亿元'},{id:9,name:'许华昌',asset:'921亿元'},{id:10,name:'钟伟杰',asset:'821亿元'}];我们导出了FUHAOS常量,以便在其它地方导入它——比如FuhaoService服务。

    同时,回到刚剪切出FUHAOS数组的app.component.ts文件,我们留下了一个尚未初始化的fuhaos属性:

    接着,我们在app目录下创建一个名叫fuhao.service.ts的文件。把这个类命名为FuhaoService,并且导出它,以供别人使用。这是个异步服务,异步返回富豪数据。

    import{Injectable}from'@angular/core';import{FUHAOS}from'./mock-fuhaos';@Injectabel()exportclassFuhaoService{getFuhaos(){returnPromise.resolve(FUHAOS);}}然后,我们在AppComponent中导入FuhaoService。

    import{FuhaoService}from'./fuhao.service';接着以依赖注入的方式告诉AppComponent如何在运行中获得一个具体的FuhaoService实例。我们在AppComponent中添加一个构造函数,同时定义一个私有属性,并给组件添加了providers元数据。

    constructor(privatefuhaoService:FuhaoService){}providers:[FuhaoService]构造函数自己什么也不用做,它在参数中定义了一个私有的fuhaoService属性,并把它标记为注入FuhaoService的靶点。

    现在,Angular将会知道,当它创建AppComponent实例时,需要先提供一个FuhaoService的实例。我们注册了一个FuhaoService提供商,来告诉注入器如何创建FuhaoService。providers数组告诉Angular,当它创建新的AppComponent组件时,也要创建一个FuhaoService的新实例。

    然后,我们在组件中使用ngOnInit生命周期钩子,让Angular在AppComponent激活时获取富豪数据。

    import{OnInit}from'@angular/core';exportclassAppComponentimplementsOnInit{ngOnInit(){this.fuhaoService.getFuhaos().then(fuhaos=>this.fuhaos=fuhaos);}}接下来,我们还要创建一个四大富豪页面,添加菜单链接,通过路由跳转到各个视图,还要在模板中格式化数据。

    为此,我们需要将Angular组件路由器加入应用中,以满足这些需求。以下是我们的计划,

    把AppComponent变成应用程序的外壳,它只负责处理导航,或者说路由把现在的AppComponent中的富豪们移到一个独立的FuhaosComponent中添加路由添加一个新的top4Component组件(四大富豪)-把四大富豪加入导航结构中我们需要把富豪列表(富豪排行榜)的显示职责从AppComponent移除,转交给新的FuhaosComponent组件,最迅速的办法就是对直接重命名:

    把app.component.ts改名为fuhaos.component.ts把AppComponent类改名为FuhaosComponent把my-app选择器改名为my-fuhaos接着,我们创建一个新的AppComponent,它将在顶部放一些导航链接,并且把我们要导航到的页面放在下面的显示区中。我们的第一个草稿看起来像这样:

    import{Component,OnInit}from'@angular/core';import{FuhaoDetailComponent}from'./fuhao-detail.component';import{FuhaoService}from'./fuhao.service';@Component({selector:'my-app',directives:[FuhaosComponent],providers:[FuhaoService],template:`

    {{title}}

    `})exportclassAppComponent{title='恒拓富豪榜';}我们希望在用户点击“富豪排行榜”之后才显示富豪列表,我们希望“导航”或者说路由跳转到富豪列表。我们需要Angular的组件路由器。首先,我们打开index.html并且在head区的顶部添加一下语句。

    Angular的组件路由是使用浏览器的history.pushState来进行路由跳转的,必须在index.html添加base标签。可前往路由器了解更多。Angular路由器是由多个服务

    (ROUTER_PROVIDERS)和多个指令

    (ROUTER_DIRECTIVES)以及一个配置装饰器(RouteConfig)组成的。我们新建一个app.routes.ts文件,然后一次性导入它们。

    import{provideRouter,RouterConfig}from'@angular/router';import{FuhaosComponent}from'./fuhaos.component';constroutes:RouterConfig=[{path:'fuhaos',component:FuhaosComponent}];exportconstappRouterProviders=[provideRouter(routes)];这个路由配置文件做了两件事情,一使用一些路由配置路由器,二提供一个导出,以便把这个路由器添加到我们的启动代码那里去。

    路由告诉路由器当用户点击链接或者把URL粘贴到浏览器地址栏时,该显示哪个视图。

    文件里的RouterConfig是一个路由定义的数组,可以包含多个路由定义对象。一个路由定义对象通常含有以下两个属性:

    path:用来匹配路由中指定的路径和浏览器地址栏中的当前路径,如/fuhaoscomponent:指明了导航到此路由时,路由器需要创建的组件,如FuhaosComponent接着,我们在main.ts中导入appRouterProviders,并通过把它添加到引导函数(bootstrap)的数组参数中让它生效。

    import{bootstrap}from'@angular/platform-browser-dynamic';import{AppComponent}from'./app.component';import{appRouterProviders}from'./app.routes';bootstrap(AppComponent,[appRouterProviders]);我们需要把router-outlet标签添加到模板的底部,RouterOutlet是ROUTER_DIRECTIVES常量中的一员。当我们在应用中导航时,路由器就把激活的组件显示在router-outlet标签里面。我们将AppComponent组件里的模板修改如下:

    template:`

    {{title}}

    富豪排行榜`,注意,a标签中的routerLink绑定,我们把RouterLink指令(ROUTER_DIRECTIVES中的一个指令)绑定到一个数组,它告诉了路由器当用户点击这个链接时,应该导航到哪里。

    我们通过一个链接参数数组定义了一个路由说明。在这个小例子中,该数组只有一个元素,一个放在引号中的路径,作为路标。回来看路由配置表,我们清楚的看到,这个路径——'/fuhaos'就是指向FuhaosComponent的那个路由的路径。

    以上是a标签的路由跳转,还有一种非a标签的路由跳转,这里也介绍一下,一般分两步走,第一步先生成路由的链接参数数组,第二步把这个数组传给路由器的navigate方法,例如:

    gotoDetail(fuhao:Fuhao){letlink=['/detail',fuhao.id];this.router.navigate(link);}这个路由参数数组有两个元素,模板路由的路径(path)和一个路由参数对象(所选富豪的id),配合这样的路由配置:

    {path:'detail/:id',component:FuhaoDetailComponent},路由部分我们就讲到这里,要完成这个需求,后面还有很多步骤,由于边幅跟时间限制,在这里就补赘述了,我们直接看最后做出来的成果。

    因篇幅问题不能全部显示,请点此查看更多更全内容