Angular和BootStrap的一个简单demo
根据Angular5高级编程这本书第二章搭建的demo
参考博客:https://blog.csdn.net/crper/article/details/64443239
代码地址:https://github.com/Harry-ZH-Wang/AngularDemo
1. 添加bootstrap包
首先ng new 项目名称创建一个Angular工程,步骤和正常创建步骤相同,然后导入BootStrap包
如果不清楚怎么构建可以看:https://www.jianshu.com/p/65e603da0828
在package.json文件中添加BootStrap CSS 的包 : "bootstrap": "4.0.0-alpha.4"
"dependencies": {
"@angular/animations": "~7.2.0",
"@angular/common": "~7.2.0",
"@angular/compiler": "~7.2.0",
"@angular/core": "~7.2.0",
"@angular/forms": "~7.2.0",
"@angular/platform-browser": "~7.2.0",
"@angular/platform-browser-dynamic": "~7.2.0",
"@angular/router": "~7.2.0",
"core-js": "^2.5.4",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26",
"bootstrap": "4.0.0-alpha.4"
}
cmd cd 到建立的项目的目录下面,执行nmp install下载bootstrap的包。
2. 添加css样式
在angular.json文件中添加bootstrap的css样式,angularJsDemo为项目名
"styles": [
"src/styles.css",
"../angularJsDemo/node_modules/bootstrap/dist/css/bootstrap.css"
]
测试下bootstrap导入是否成功,我们修改下src下面的index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularJsDemo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body class="m-a-1">
<h3 class="bg-primary p-a-1">测试列表</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-bordered table-striped">
<thead>
<tr>
<td>标题</td>
<td>描述</td>
</tr>
</thead>
<tbody>
<tr>
<td>第一行</td>
<td>no</td>
</tr>
<tr>
<td>第二行</td>
<td>no</td>
</tr>
<tr>
<td>第三行</td>
<td>no</td>
</tr>
</tbody>
</table>
</body>
</html>
启动一下,bootStrap的样式生效
这里只是做了个静态页面的展示,只是为了测试,下面按照书中的代码示例,添加Angular的功能
3. HTML页面添加Angular功能
通过cli建立的demo,在app目录下其实已经生成了一套配置的文件代码,这里为了自己体验下逻辑,就自己仿照着配置下
首先body 内容去掉,添加<demo-app>Angular 入口</demo-app> 标签,这里demo-app标签不是html标签,是自己随便写的一个,后续作为单页面APP的入口
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularJsDemo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body class="m-a-1">
<app-demo>Angular 入口</app-demo>
</body>
</html>
这里直接用TypeScript,它是javaScript的一个超集,除了自己的语法,也支持原生态的javaScript语法。在src/app 目录下新建一个demo文件夹,存放我们自己的TS文件,这里在demo文件夹下新建helloTS.ts,这里可以直接写JavaScript,不过既然玩新东西,那肯定要用TypeScript。
helloTs.ts文件
// 在创建JavaScript模块时,export 语句用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们
/**
* 这里的类做原始数据来源
*/
export class HelloModel {
user;
items;
/**
* 在一个类中只能有一个名为 “constructor” 的特殊方法。
* 一个类中出现多次构造函数 (constructor)方法将会抛出一个 SyntaxError 错误。
* 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
* 如果没有显式指定构造方法,则会添加默认的 constructor 方法。
* 如果不指定一个构造函数(constructor)方法, 则使用一个默认的构造函数(constructor)。
*/
constructor() {
this.user = 'Admin';
this.items = [new HelloItem('第一行', false),
new HelloItem('第二行', false),
new HelloItem('第三行', false)];
}
}
/**
* 数据对像类
*/
export class HelloItem {
action;
done;
constructor(action, done) {
this.action = action;
this.done = done;
}
}
这一步是构造一个页面展示的数据,实际情况数据来源应该是服务器来的,这里的demo,就前端构造一个数据对像列表,非必须。
3.1 创建模板
在angular中,向用户展示数据是通过模板来实现的,{{}} 这表示数据绑定
helloComponent.html 文件
<!-- Angular demo 模板类 -->
<!--{{}}是angular的数据绑定取值,这里getUser()是自己写的函数-->
<h3 class="bg-primary p-a-1">{{getName()}}的测试列表</h3>
3.2 创建组件
Angular组件负责为模块提供所需数据合逻辑
helloComponent.ts文件
import { Component } from '@angular/core';
import { HelloModel} from './helloTs';
/**
* @Component 标记为一个装饰器(组件)
* selector: 'demo-app' 指定一个CSS选择器,匹配该组件要应用的HTML元素,这里就是我们刚刚自定义的元素
* templateUrl: 'helloComponent.html' 模板的路径,这里写的相对路径 也可以写绝对路径 app/demo/helloComponent.html
*/
@Component({
selector: 'app-demo',
templateUrl: 'helloComponent.html'
})
/**
* 实例化一个对象
*/
export class AppHelloComponent {
model = new HelloModel();
getName() {
return this.model.user;
}
}
3.3 定义装饰器
通过@NgModule定义的属性来提供配置信息
helloModules.ts文件
import { BrowserModule } from '@angular/platform-browser';
// 每个模块的定义必须有这个才能生效,ng2的开发模式就是类似一个树,从根节点无限发散
import { NgModule } from '@angular/core';
// 表单模块,比如你要在组件内用到一些表单元素或者数据绑定,不然会报错
import { FormsModule } from '@angular/forms';
// 自己定义的组件
import {AppHelloComponent} from './helloComponent';
@NgModule({
declarations: [ // 指令和组件
AppHelloComponent
],
imports: [ // 比如你要引用那些模块的功能就要引入
BrowserModule,
FormsModule
],
providers: [], // 服务
bootstrap: [AppHelloComponent] // 启动的模块,一个app一般只有一个启动模块!
})
export class AppModule { }
3.4 配置main.ts引到文件
main.ts文件
// 引入生产模式,控制关闭开发模式的,函数控制
import { enableProdMode } from '@angular/core';
// app启动模块,必须引入
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
// import { AppModule } from './app/app.module';
// 根模块,程序启动根页面
import { AppModule} from './app/demo/helloModules';
// 环境配置文件,可以写入接口路径什么的。。dev,prod各一份
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
// platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
// bootstrapModule是PlatformRef的一个方法,这个方法中实现了Module的初始化、Component的初始化等,是Angular的启动函数,此方法是基于浏览器,如果是移动例如Ionic框架,引到方法不一样
platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
配置完成了,启动测试下
4. 继续完善demo
4.1继续完善demo,通过Angular内置的结构指令加载List
三个常用的内置结构型指令: NgIf、NgFor和NgSwitch
中文手册地址:https://angular.cn/guide/structural-directives
首先添加一个getItems()方法获得之前构造的List
helloComponent.ts 文件
import { Component } from '@angular/core';
import { HelloModel} from './helloTs';
/**
* @Component 标记为一个装饰器(组件)
* selector: 'demo-app' 指定一个CSS选择器,匹配该组件要应用的HTML元素,这里就是我们刚刚自定义的元素
* templateUrl: 'helloComponent.html' 模板的路径,这里写的相对路径 也可以写绝对路径 app/demo/helloComponent.html
*/
@Component({
selector: 'app-demo',
templateUrl: 'helloComponent.html'
})
/**
* 实例化一个对象
*/
export class AppHelloComponent {
model = new HelloModel();
getName() {
return this.model.user;
}
getItems() {
return this.model.items;
}
}
使用内置的结构指令*ngFor循环列表 * 号不能省略
helloComponent.html 文件
<!-- Angular demo 模板类 -->
<!--{{}}是angular的数据绑定取值,这里getUser()是自己写的函数-->
<h3 class="bg-primary p-a-1">{{getName()}}的测试列表</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<td>No</td>
<td>标题</td>
<td>描述</td>
</tr>
</thead>
<tbody>
<!--nfFor ngSwitch 为Angular的内置结构指令,*不能省略,index为数组的索引,0开始-->
<tr *ngFor="let item of getItems(); let i = index">
<td>{{i + 1}}</td>
<td>{{item.action}}</td>
<td [ngSwitch] = "item.done">
<span *ngSwitchCase="true">已办</span>
<span *ngSwitchCase="false">代办</span>
</td>
</tr>
</tbody>
</table>
到这来就完成了数据的单向绑定,也就是展示的步骤
4.2 创建数据双向绑定
这来使用ngModel 来实现双向绑定,ngModel有三种写法,ngModel、[ngModel]和[(ngModel)]
[ngModel]为单向绑定,操作不会改变原有的值,[(ngModel)]为双向绑定,会改变原有值
简单说就是当你想从html的 input 组件去改动.ts对应的变量,,反之更动.ts的变量html对应的值也会改变,这时候就要使用双向绑定的功能
helloComponent.html文件
<!-- Angular demo 模板类 -->
<!--{{}}是angular的数据绑定取值,这里getUser()是自己写的函数-->
<h3 class="bg-primary p-a-1">{{getName()}}的测试列表</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<td>No</td>
<td>标题</td>
<td>描述</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<!--nfFor ngSwitch 为Angular的内置结构指令,*不能省略,index为数组的索引,0开始-->
<tr *ngFor="let item of getItems(); let i = index">
<td>{{i + 1}}</td>
<td>{{item.action}}</td>
<td [ngSwitch] = "item.done">
<span *ngSwitchCase="true">已办</span>
<span *ngSwitchCase="false">代办</span>
</td>
<td>
<input type="checkbox" [(ngModel)] = "item.done" />
</td>
</tr>
</tbody>
</table>
勾选checkbox后可以发现代办变为了已办
4.3 lambda表达式
这来可以通过一些语法糖来做些数据过滤,例如通过lambda函数来做数据过滤,这个时候勾选了后的数据会消失
helloComponent.ts 文件
import { Component } from '@angular/core';
import {HelloItem, HelloModel} from './helloTs';
/**
* @Component 标记为一个装饰器(组件)
* selector: 'demo-app' 指定一个CSS选择器,匹配该组件要应用的HTML元素,这里就是我们刚刚自定义的元素
* templateUrl: 'helloComponent.html' 模板的路径,这里写的相对路径 也可以写绝对路径 app/demo/helloComponent.html
*/
@Component({
selector: 'app-demo',
templateUrl: 'helloComponent.html'
})
/**
* 实例化一个对象
*/
export class AppHelloComponent {
model = new HelloModel();
getName() {
return this.model.user;
}
getItems() {
// filter 从数组项中选择一个子集,=>为lambda表达式(参数1, 参数2, …, 参数N) => { 函数声明 },这段代码等同于 function(item){return !item.done}
return this.model.items.filter(item => !item.done);
}
}
上面做了删除的事件,这里再做个添加的事件
helloComponent.ts 文件
<!-- Angular demo 模板类 -->
<!--{{}}是angular的数据绑定取值,这里getUser()是自己写的函数-->
<h3 class="bg-primary p-a-1">{{getName()}}的测试列表</h3>
<div class="m-t-1 m-b-1">
<!-- #textValue为取值的 -->
<input class="form-control" #textValue />
<button class="btn btn-primary m-t-1" (click)="addInfo(textValue.value)">Add</button>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<td>No</td>
<td>标题</td>
<td>描述</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<!--nfFor ngSwitch 为Angular的内置结构指令,*不能省略,index为数组的索引,0开始-->
<tr *ngFor="let item of getItems(); let i = index">
<td>{{i + 1}}</td>
<td>{{item.action}}</td>
<td [ngSwitch] = "item.done">
<span *ngSwitchCase="true">已办</span>
<span *ngSwitchCase="false">代办</span>
</td>
<td>
<input type="checkbox" [(ngModel)] = "item.done" />
</td>
</tr>
</tbody>
</table>
helloComponent.ts
import { Component } from '@angular/core';
import {HelloItem, HelloModel} from './helloTs';
/**
* @Component 标记为一个装饰器(组件)
* selector: 'demo-app' 指定一个CSS选择器,匹配该组件要应用的HTML元素,这里就是我们刚刚自定义的元素
* templateUrl: 'helloComponent.html' 模板的路径,这里写的相对路径 也可以写绝对路径 app/demo/helloComponent.html
*/
@Component({
selector: 'app-demo',
templateUrl: 'helloComponent.html'
})
/**
* 实例化一个对象
*/
export class AppHelloComponent {
model = new HelloModel();
getName() {
return this.model.user;
}
getItems() {
// filter 从数组项中选择一个子集,=>为lambda表达式(参数1, 参数2, …, 参数N) => { 函数声明 },这段代码等同于 function(item){return !item.done}
return this.model.items.filter(item => !item.done);
}
addInfo(info) {
if (info !== '') {
this.model.items.push(new HelloItem(info, false));
}
}
}
这里就完成了一个简单的前端demo,做个备注