Angular2 不明真相第一个Demo例子

如果不是去年换工作接触到AngularJS,估计是不会花时间去学习这个框架的,毕竟是前端的框架,不是自己熟悉的领域。但是为了混得下去,去年就学习了AngularJS的一些用法,当时还整理了一些积累 《AnguarJS测试的实施步骤整理》。

原以为可以凑合够用应付项目开发,没想到上个月公司前端扛大旗的人就说要使用Angular2,现有的AnagularJS 1.XX版本的代码会逐步升级到Angular2。去年就听说了AngularJS已经升级了,并且跟typescript联姻了,还听说typescript的语法跟C#很类似,说什么后台程序员学Angular2没有什么问题。也没有实际去学习,但目前项目需要用到,所以最近就启动了Angular2的学习过程,不指望在短期内精通,总得在新技术落地之前自己有个基础的知识,不至于手忙脚乱,也显得自己淡定。

接着讲讲Angular2,为什么少了JS?这就是最大的升级嘛?这也是个升级,没毛病。之前AngularJS的名称用于1.XXX版本,去年7月份Angular正式发布了2.0版本,也就这里说的Angular2。2.0版本几乎是break changes,也就是说跟之前的版本不兼容了,几乎推翻重来了,所以苦逼开发者还得重复学习轮子。新版本引入了typescript,typescript是javascript的超集,通过typescript可以生成javascript代码。然后还提出了很多新的概念,比如component,import,新的module,新的指令等等。总之有得你去学习。

这里不深入分析各个模块,自己也刚了解不久,这篇博文演示用Angular2创建一个Demo例子,用于直观感受,提提学习兴趣,找找自信心。

一、准备环境

a.安装Node.js和NPM

步骤不说了,安装完成之后命令行node –v, npm -v看看版本,比如我的分别是v6.9.2和3.10.9

b.找个开发工具,这里使用visual studio code,简单快捷

二、准备项目

a.准备package.json文件

新建一个目录todo/app

mkdir –p todo/app

然后cd到todo目录,新建一个package.json文件,使用过node.js的应该知道这是干嘛的,类似于asp.net core的project.json,定义了一些依赖内容。

package.json

{

"dependencies": {

"@angular/common": "2.2.0",

"@angular/compiler": "2.2.0",

"@angular/core": "2.2.0",

"@angular/forms": "2.2.0",

"@angular/platform-browser": "2.2.0",

"@angular/platform-browser-dynamic": "2.2.0",

"reflect-metadata": "0.1.8",

"rxjs": "5.0.0-beta.12",

"zone.js": "0.6.26",

"core-js": "2.4.1",

"classlist.js": "1.1.20150312",

"systemjs": "0.19.40",

"bootstrap": "4.0.0-alpha.4"

},

"devDependencies": {

"lite-server": "2.2.2",

"typescript": "2.0.3",

"typings": "1.4.0",

"concurrently": "3.1.0"

},

"scripts": {

"start": "concurrently \"npm run tscwatch\" \"npm run lite\" ",

"tsc": "tsc",

"tscwatch": "tsc -w",

"lite": "lite-server",

"typings": "typings"

}

}

看起来又是一堆面条,这里暂时从字面意思知道三大块的意思

dependencies:运行程序需要用到的依赖组件

dveDependencies:用于开发环境的依赖组件

scripts:可在命令行运行的脚本,这里包含了TypeScript的编译器和开发时用到的HTTP server

准备了package.json之后,执行如下命令

npm install

这是讲package.json的依赖的包下载到本地,可以理解为nuget的restore,这个命令需要些时间,稍等。

image

下载完成之后,那么在todo目录下会新增一个node_modules目录,都是些依赖包信息。

b.配置TypeScript编译器

之前提到Angular2可用Typescript生成JS代码,这是新版的重大卖点,用typescript可以利用些高级特性生成复杂的JS代码,同时也为开发人员省去了对兼容性的考虑。

在todo目录下创建如下tsconfig.json文件

{

"compilerOptions": {

"target": "es5",

"module": "commonjs",

"moduleResolution": "node",

"emitDecoratorMetadata": true,

"experimentalDecorators": true

},

"exclude": [

"node_modules"

]

}

c.新建一个Index.html

好了回到最原始的一个文件,还是在todo目录下,内容如下

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>ToDo</title>

<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />

</head>
<body>
<h1>Content will go here</h1>
</body>
</html>

到此基本项目已经准备好,在todo目录运行用visual studio code打开,目录结构应该是这样的

image

然后好奇这个简单的项目能运行吗,当然可以。在todo目录下运行如下命令

npm start

image

然后根据提供的Access URL,在浏览器打开就可以了(实际运行之后FireFox自动就开打了这个URL)

image

就显示一行内容而已,不过也证明了是可以运行的。

通过上面的命令行可以看到实际上是运行了一个简单的HTTP Server,这个server还会监控index.html的页面变化,并实时在浏览器自动刷新显示最新的内容。比如我们把index.html更新为如下内容

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>ToDo</title>

<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />

</head>

<body class="m-a-1">
<h3 class="bg-primary p-a-1">Junwen's To Do List</h3>
<div class="m-t-1 m-b-1">
<input class="form-control" />
<button class="btn btn-primary m-t-1">Add</button>
</div>

<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Description</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr><td>Buy Flowers</td><td>No</td></tr>
<tr><td>Get Shoes</td><td>No</td></tr>
<tr><td>Collect Tickets</td><td>Yes</td></tr>
<tr><td>Call Joe</td><td>No</td></tr>
</tbody>
</table>
</body>
</html>

那么浏览器的内容会自动更新为如下

image

三、将Angular框架引入到项目中

更新index.html文件,更新为

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>ToDo</title>

<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />

<script src="node_modules/classlist.js/classList.min.js"></script>
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.min.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>

</head>
<body class="m-a-1">
<todo-app>Angular placeholder</todo-app>
</body>
</html>

这里引入了一些Angular项目需要依赖的JS文件,并且将body的内容更改成了一个自定义的标记,是不是感觉又回到了ASP.NET Core。

目前这里todo-app的标记,浏览器是没法识别和解析的,所以直接原样输出了内容

image

 

实现todo-app指令

接下来就是要实现todo-app的内容,切换到todo/app目录

a.新建model.ts文件

没错这就是我们要写的第一个typescript文件,内容如下

export class Model{

user:

items;

constructor(){

this.user = "Junwen Luo";

this.items = [

new ToDoItem("Firt Item", false),

new ToDoItem("Second Item", true),

new ToDoItem("Third Item", false),

new ToDoItem("Fourth Item", false)

];

}

}

export class ToDoItem{

action;

done;

constructor(action, done){

this.action = action;

this.done = done;

}

}

大致的意思就是新建了两个类,分别是Model和ToDoItem,然后有各自的构造方法,是不是很熟悉的套路呢。

这个语法浏览器当然不认账啦,.ts什么鬼,之前提到ts是javascript的超集,那么会在typescript编译器会将.ts文件生成对应的.js代码文件,保存.ts之后应该会生成一个model.js文件,代码如下

"use strict";

var Model = (function () {

function Model() {

this.user = "Junwen Luo";

this.items = [

new ToDoItem("Firt Item", false),

new ToDoItem("Second Item", true),

new ToDoItem("Third Item", false),

new ToDoItem("Fourth Item", false)

];

}

return Model;

}());

exports.Model = Model;

var ToDoItem = (function () {

function ToDoItem(action, done) {

this.action = action;

this.done = done;

}

return ToDoItem;

}());

exports.ToDoItem = ToDoItem;

如果代码没有自动生成,可以重新运行npm start。

b.新建一个模板,还是在app目录下,新建文件名为app.component.html

<h3 class="bg-primary p-a-1">{{getName()}}'s To Do List</h3>

<div class="m-t-1 m-b-1">

<input class="form-control" #todoText>

<button class="btn btn-primary m-t-1" (click)="addItem(todoText.value)">

Add

</button>

</div>

<table class="table table-striped table-bordered">

<thead>

<tr>

<th></th>

<th>Description</th>

<th>Done</th>

<th></th>

</tr>

</thead>

<tbody>

<tr *ngFor="let item of getTodoItems(); let i = index">

<td>{{i+1}}</td>

<td>{{item.action}}</td>

<td><input type="checkbox" [(ngModel)]="item.done" /></td>

<td [ngSwitch]="item.done">

<span *ngSwitchCase="true">Yes</span>

<span *ngSwitchDefault>No</span>

</td>

<td>

<button (click)="removeItem(i)">Delete</button>

</td>

</tr>

</tbody>

</table>

这里{{}}表示的是绑定的内容,应该很好理解。

这个模板提供了显示列表,添加和删除Item的功能,其中使用了*ngFor,*ngSwitch,*ngSwitchDefault,ngModel等这些指令。

ngModel是用于双向绑定

(click)是绑定单击事件

*ngFor都比较好理解,for循环嘛

c.新建app.component.ts,内容如下

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

import { Model, ToDoItem } from "./model";

@Component({

selector: "todo-app",

templateUrl: "app/app.component.html"

})

export class AppComponent {

model = new Model();

getName() {

return this.model.user;

}

getTodoItems() {

return this.model.items;

}

addItem(newItem) {

if (newItem != "") {

this.model.items.push(new ToDoItem(newItem, false));

}

}

removeItem(index) {

console.log(index);

if (index >= 0) {

this.model.items.splice(index, 1);

}

}

}

这里创建一个组件,意思是匹配到todo-app的标记都要通过templateUrl对应的模板来解析显示。

然后还定义一个类和方法,感觉像Controller。

import的作用就是导入需要依赖的内容,类似于命名空间引入吧。

d.新建app.module.ts

上一个文件只是一个Component,当然还是不能够直接运行,需要通过一个Module来封装,更1.XXX版本的思想理念是一致的。

app.module.ts内容如下

import { NgModule } from "@angular/core";

import { BrowserModule } from "@angular/platform-browser";

import { FormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";

@NgModule({

imports:[BrowserModule, FormsModule],

declarations:[AppComponent],

bootstrap:[AppComponent]

})

export class AppModule{}

e.新建main.ts

到此还不能运行了,还需要一个入口,可以理解为main方法吧。

import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app.module";

platformBrowserDynamic().bootstrapModule(AppModule);

f.更新index.html文件

上面都定义好了Angular的内容,那需要加入到index.html页面中,在原有的head加入如下scripts

<script>
var paths = {
"rxjs/*": "node_modules/rxjs/bundles/Rx.min.js",
"@angular/*": "node_modules/@angular/*"
}
var packages = { "app": {} };
var angularModules = ["common", "compiler", "core", "forms",
"platform-browser", "platform-browser-dynamic"];
angularModules.forEach(function (pkg) {
packages["@angular/" + pkg] = {
main: "/bundles/" + pkg + ".umd.min.js"
};
});
System.config({ paths: paths, packages: packages });
System.import("app/main").catch(function(err){ console.error(err); });
</script>

看起来很麻烦吧,没错就是这样,到这里应该就完成了,这样html页面就跟Angular胜利会师了,看看运行的效果

image

CRD没有U的功能就这么简单实现,只当做第一个体验学习吧。

 

代码路径

https://github.com/shenba2014/ProAngular2ndExamples/tree/master/FirstAngularApp/

posted @ 2017-04-16 10:39  神八  阅读(3490)  评论(2编辑  收藏  举报