导图社区 Angular7运行机制
Angular7运行机制--腾讯课堂:米斯特吴 《Angular4从入门到实战》学习体会。
编辑于2019-02-17 05:44:02Angular7 运行机制
项目目录解析
项目根目录
angular.json 命令行工具配置文件 或叫编译依赖文件
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "try": { "root": "", "sourceRoot": "src", /*启动目录,默认指向src目录*/ "projectType": "application", "prefix": "app", "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/try", "index": "src/index.html", /* 启动时加载的页面 默认指向src目录中index.html*/ "main": "src/main.ts", /* 启动时加载的脚本 默认指向src目录中的main.ts*/ "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets" ], /*后面省略*/
main.ts 入口主程序
detail
// 导入enableProdMode用来关闭angular开发者模式 import { enableProdMode } from '@angular/core'; // 负责从angular浏览器模块中导入platformBrowserDynamic这个方法, // 这个方法告诉angular使用哪个模块来启动整个应用 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; // 整个应用的主模块,也是核心引导程序 import { AppModule } from './app/app.module'; /*#####入口程序调用app.module.ts*/ // angular多环境支持 import { environment } from './environments/environment'; if (environment.production) { // 如果是工厂模式,就启动enableProdMode来关闭开发者模式 enableProdMode(); } // 调用bootstrapModule方法来传入AppModule作为启动模块来启动应用。 platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.error(err));
index.html
detail
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>A4app</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="stylesheet" href="https://bootswatch.com/4/cosmo/bootstrap.min.css"> </head> <body> <app-root></app-root> </body> </html>
项目主目录app
app.module.ts (总调度室)
detail
//Angular 模块类描述应用的部件是如何组合在一起的,引导并运行应用。常规名字是 AppModule,即 app.module.ts文件/*引入组件*/ import { BrowserModule } from '@angular/platform-browser'; /*BrowserModule,浏览器解 析的模块*/ import { NgModule } from '@angular/core'; /*angualrjs 核心模块*/ import { FormsModule } from '@angular/forms'; /*表单数据绑定 表单验证需要的模块*/ import { HttpClientModule} from '@angular/common/http'; /*数据请求模块*/ import { RouterModule,Routes} from '@angular/router'; import { AppComponent } from './app.component'; /*根组件,调用app.component.ts文件*/ //以下五个组件是创建新组建时自动加入到这里的(因手建故DataService是手动添加的) import { UserComponent } from './components/user/user.component'; import { HomeComponent } from './components/home/home.component'; import { DataService} from './services/data.service'; import { NavbarComponent } from './components/navbar/navbar.component'; import { UserDetailComponent } from './components/user-detail/user-detail.component'; const appRoutes:Routes = [ /*定义路径常量*/ { path: '',component:HomeComponent}, { path: 'user',component:UserComponent}, { path: 'user/:id',component:UserDetailComponent}, ]; /*@NgModule 装饰器将 AppModule 标记为 Angular 模块类(也叫 NgModule 类)。*/ /*@NgModule 接受一个元数据对象,告诉 Angular 如何编译和启动应用。*/ @NgModule({ declarations: [ /*引入当前项目运行的组件,创建自定义组件时自动生成的*/ AppComponent, UserComponent, HomeComponent, NavbarComponent, UserDetailComponent ], imports: [ /*引入当前模块运行依赖的其他模块,为什么NgModule没有引入进来?*/ BrowserModule, FormsModule, HttpClientModule, RouterModule.forRoot(appRoutes) ], providers: [DataService], /*定义的服务 回头放在这个里面,自定义的服务*/ bootstrap: [AppComponent] /* 指定应用的主视图(称为根组件) 通过引导根 AppModule 来启动 应用 ,这里一般写的是根组件*/ }) /*根模块不需要导出任何东西, 因为其它组件不需要导入根模块。 但是一定要写*/ export class AppModule { }
子主题
app.component.ts
detail
import { Component } from '@angular/core'; /*引入angular内核*/ @Component({ /*@Component元数据装饰器,所有的组件都必须用一个@Component装饰器来注解*/ selector: 'app-root', /*指定选择器app-root, 通常是用来修饰index.html标签<app-root>*/ templateUrl: './app.component.html', /*为选择器app-root指定了展示的模板,它决定了将在index.html的标签*/ /*<app-root>中展示什么,以及是否再指定标签往下一层展示*/ styleUrls: ['./app.component.css'] /*为选择器app-root制定了展示的样式*/ //template:'<div>Hello World!</div>', /*也可以用下面的这两句代替上面的两句,但一般不这么做*/ //styles:['div{width: 200px;height: 200px; background-color: #0f0;}'] }) export class AppComponent { /*定义有关组件的属性和方法及大部分的逻辑,并导出到@Component所指定的html模板中*/ //AppComponent就是一个标准的typeScript类,类里面没有框架的痕迹,就是用装饰器将元数据附加到AppComponent类上, title = 'Hello Yeastoday'; //属性值会被展示到模板中 }
// 1.组件元数据装饰器@Component,简称装饰器,用来告知angular框架如何处理一个typeScript类。 component装饰器包含多个属性,这些属性的值叫做元数据,angular会根据这些属性的值来渲染组件并执行组件的逻辑 // 2.模板:通过组件自带的模板来定义组件的外观,模板是以HTML的形式存在,告诉angular应该如何来渲染组件,一般来说,模板看起来很像html,但是我们可以再模板中使用angular的数据绑定语法来呈现控制器中的数据 // 3.控制器【controller】:控制器就是普通的typeScript类,他会被@component装饰器来装饰,控制器会包含组件所有的属性和方法,绝大多数的页面逻辑都是写在控制器里,控制器通过数据绑定与模板来通讯,模板展现控制器的数据,控制器处理模板上发生的事件 //4.数据绑定{{title}},就是模板的各个部分与控制器的各个部分相互作用的一个机制,我们在模板中添加绑定标记,如何把二者联系起来{{title}}最常见的将控制器的值绑定到模板中的绑定方法,叫做差值表达式 //5.输入属性:@inputs(),用来接收外部传入的数据的,输入属性使得父组件直接传递数据给子组件,angular程序其实就是一个组件树,输入属性允许你在组件树中传递数据。 //6.提供器 providers,用来做依赖注入的。 //7.生命周期钩子 lifeCycle Hooks,在一个组件从创建到销毁的过程中有多个钩子可以被用来触发,来执行各种业务数据,举例,在一个组件被实例化的时候,执行一段初始化的逻辑,从后台读取数据进到组件里面去。 //8.样式表 styles,组件可以关联一些样式表文件,可选的 //9.动画 angular提供了一个动画包来张建组件的动画效果 //10.输出属性@Outputs(),与前面的输入属性相对的,定义一个其他组件感兴趣的事件或者在组件间共享数据
app.component.html (模板展示总页)
detail
<!--<app-user></app-user>--> <!--<app-home></app-home>--> <app-navbar></app-navbar> <router-outlet></router-outlet>
app.component.css
services目录
data.service.ts
detail
import {Injectable} from '@angular/core'; /*引入Injectable*/ import { HttpClient} from '@angular/common/http'; // import 'rxjs/add/operator/map'; HttpClient返回的就是json数据了,所以这个引入废弃了 @Injectable() /*调用Injectable*/ export class DataService{ constructor(public http:HttpClient){ /*创建对象http以此调用get、post等*/ } getSingleUser(id){ return this.http.get("http://jsonplaceholder.typicode.com/users/"+id) } getUsers(){ return this.http.get("http://jsonplaceholder.typicode.com/users") // .map(res => res.json()); HttpClient返回的就是json数据了,所以不再需要转换了 } addUser(user){ return this.http.post("http://jsonplaceholder.typicode.com/users",user) } deleteUser(id){ return this.http.delete("http://jsonplaceholder.typicode.com/users/"+id) } updataUser(user){ return this.http.put("http://jsonplaceholder.typicode.com/users/"+user.id,user) } }
components目录
user组件目录
user.component.ts
detail
import { Component, OnInit } from '@angular/core'; /*引入angular核心*/ import {DataService} from '../../services/data.service'; @Component({ selector: 'app-user', /*使用这个组件的名字*/ templateUrl: './user.component.html', styleUrls: ['./user.component.css'] }) export class UserComponent implements OnInit { /*实现接口*/ name: string; age: number; email: string; address: Address; hobbies: string[]; hello: any; isEdit:boolean = false; constructor(public dataService:DataService) { /*构造函数*/ console.log("constructor ran ..."); //Observable //this.user = this.dataService.getUsers(); } ngOnInit() { /*初始化加载的生命周期函数*/ console.log("ngOnInit ran ..."); this.name = "Hemiah"; this.age = 30; this.email = "test@test.com"; this.address = { street: "定泗路", city: "北京", state: "昌平区" }; this.hobbies = ["写代码", "看电影", "听音乐"]; } onClick() { // console.log(123); this.name = "Mr.Wu"; this.hobbies.push("New Hobby"); /*push追加到后面*/ } addHobby(hobby){ // console.log(hobby); this.hobbies.unshift(hobby); /* unshift插入到前面*/ return false; } deleteHobby(i){ this.hobbies.splice(i,1); /*splice删除,从下标开始1个项目*/ } toggleEdit(){ this.isEdit= !this.isEdit; } } interface Address{ street:string, city:string, state:string }
user.component.html
detail
<h1>Hello {{name}}!</h1> <!--数据绑定--> <ul> <li>年龄:{{age}}</li> <li>邮箱:{{email}}</li> <li>地址:{{address.city}}{{address.state}}{{address.street}}</li> </ul> <!--ngFor循环--> <ul> <li *ngFor="let hobby of hobbies;let i='index'"> {{i+1}}:{{hobby}} <!-- 好神奇--> <button (click)="deleteHobby(i)">X</button> </li> </ul> <!--事件--> <button (click)="onClick()">点我</button> <!--表单--> <form (submit)="addHobby(hobby.value)"> <div> <label for="hobby">爱好:</label> <input type="text" #hobby> <!-- #号是必须的,名字可以自由起--> </div> </form> <hr> <button (click)="toggleEdit()">是否编辑用信息</button> <!--编辑表单--> <div *ngIf="isEdit"> <!--控制div组件是否可见--> <h1>编辑用户信息</h1> <form> <div> <label for="name">姓名:</label> <input type="text" [(ngModel)]="name" name="name"> <!--双向数据绑定实现编辑功能--> <!--使用ngModel必须要在app下的app.module.ts文件中引入 import { FormsModule} from '@angular/forms'; 还要在此文的imports:[]中添加上:FormsModule 注:Angular2是自动添加的--> </div> <div> <label for="age">年龄:</label> <input type="text" [(ngModel)]="age" name="age"> </div> <div> <label for="city">城市:</label> <input type="text" [(ngModel)]="address.city" name="city"> </div> </form> </div> <hr> <!--Observable--> <!--<ul> <li *ngFor="let user of users"> {{user}} </li> </ul>-->
user.component.css
home组件目录
home.component.ts
detail
import { Component, OnInit } from '@angular/core'; import { DataService} from '../../services/data.service'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { users:any[]; user = { id:"", name:"", email:"", phone:"" } isEdit:boolean = false; constructor(public dataService:DataService) { this.dataService.getUsers().subscribe(users=>{ /*观察者对象下的订阅者模式*/ // console.log(users); /*观察控制台数据是否正确输出*/ this.users = users; }) } onSubmit(isEdit){ if (isEdit){ /*如果isEdit=true则执行put方法进行编辑编辑*/ this.dataService.updataUser(this.user).subscribe(user=>{ //删除当前的 for(let i=0;i<this.users.length;i++){ if(this.users[i].id==this.user.id){ this.users.splice(i,1); } } //添加更新的 this.users.unshift(this.user); }) } else { /*如果isEdit=fales则执行post方法*/ this.dataService.addUser(this.user).subscribe(user=>{ // console.log(user); /*查看控制台输出*/ this.users.unshift(user); /*直接显示在html页面中*/ }) } } onDeleteClick(id){ // console.log(id); this.dataService.deleteUser(id).subscribe(res=>{ for(let i=0;i<this.users.length;i++){ if(this.users[i].id==id){ this.users.splice(i,1); } } }) } onEditClick(user){ this.isEdit=true; this.user=user; /*先把值传到输入框(编辑框)内*/ } ngOnInit() { } }
home.component.css
home.component.html
detail
<div class="container"> <form (submit)="onSubmit(isEdit)"> <!--添加一个form和提交触发事件--> <div class="form-group"> <label>姓名</label> <input type="text" class="form-control" [(ngModel)]="user.name" name="name"> </div> <div class="form-group"> <label>邮箱</label> <input type="text" class="form-control" [(ngModel)]="user.email" name="email"> </div> <div class="form-group"> <label>电话</label> <input type="text" class="form-control" [(ngModel)]="user.phone" name="phone"> </div> <input type="submit" class="btn btn-success" value="提交"> </form> <hr> <div *ngFor="let user of users"> <div class="well"> <!--因为在index.html已经引入了CSS模板--> <ul class="list-group"> <li class="list-group-item">姓名:{{user.name}}</li> <li class="list-group-item">邮箱:{{user.email}}</li> <li class="list-group-item">电话:{{user.phone}}</li> </ul> <button (click)="onEditClick(user)" class="btn btn-danger">编辑</button> <button (click)="onDeleteClick(user.id)" class="btn btn-danger">删除</button> <a class="btn btn-primary pull-right" [(routerLink)]="'/user/'+user.id">详情</a> </div> </div> </div>
navbar组件目录
navbar.component.ts
detail
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-navbar', templateUrl: './navbar.component.html', styleUrls: ['./navbar.component.css'] }) export class NavbarComponent implements OnInit { constructor() { } ngOnInit() { } }
navbar.component.html
detail
<nav class="navbar navbar-light"> <div class="container"> <a class="navbar-brand" href="#">Angular4</a> <div id="navbar" class="navbar-collapse"> <ul class="nav navbar-nav"> <li><a href="#" routerLink="/">Home</a></li> <li><a href="#" routerLink="/user">User</a></li> </ul> </div> </div> </nav>
navbar.component.css
user-detail组件目录
user-detail.component.ts
detail
import { Component, OnInit } from '@angular/core'; import { Router,ActivatedRoute,Params} from '@angular/router'; import {DataService} from '../../services/data.service'; @Component({ selector: 'app-user-detail', templateUrl: './user-detail.component.html', styleUrls: ['./user-detail.component.css'] }) export class UserDetailComponent implements OnInit { id:number; user:object={}; constructor( public dataServicde:DataService, private route:ActivatedRoute, private router:Router ) { this.route.params.subscribe((params:Params)=>{ // console.log(params.id); this.id=params.id; }) } ngOnInit() { this.dataServicde.getSingleUser(this.id).subscribe((user)=>{ // console.log(user); this.user=user; }) } }
user-detail.component.html
detail
<ul class="list-group"> <li class="list-group-item">{{user.id}}</li> <li class="list-group-item">{{user.name}}</li> <li class="list-group-item">{{user.email}}</li> <li class="list-group-item">{{user.phone}}</li> <li class="list-group-item">{{user.website}}</li> </ul>
user-detail.component.css
初建项目时的 初期运行机制 angular的工作机制 1.加载html,然后解析成DOM; 2.加载angular.js脚本; 3. AngularJS等待DOMContentLoaded事件的触发; 4. AngularJS寻找ng-app指令,根据这个指令确定应用程序的边界; 5.使用ng-app中指定的模块配置$injector; 6.使用injector创建injector创建compile服务和$rootScope; 7.使用compile服务编译DOM并把它链接到compile服务编译DOM并把它链接到rootScope上; 8. ng-init指令对scope里面的变量name进行赋值; 9.对表达式{{name}}进行替换,于是乎,显示为“Hello World!”
main.ts
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.error(err));
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; }
index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Media</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> <app-root></app-root> </body> </html>
main.ts 入口程序
app.module.ts (总调度室)
app.component.ts
app.component.html (模板展示总页)
index.html
user.component.ts
user.component.html
home.component.ts
home.component.html
navbar.component.ts
navbar.component.html
user-detail.component.ts
user-detail.component.html
data.service.ts