Angular2 :从 beta 到 release4.0 版本升级总结

一、版本说明

原始版本: 2.0.0-beta.6

目标版本: 4.1.1

新增脚手架: Angular-cli

脚手架版本: 1.0.0-rc.1

升级后主要依赖版本如下:


"dependencies": {
    "@angular/common": "^4.0.0",
    "@angular/compiler": "^4.0.0",
    "@angular/compiler-cli": "^4.0.0",
    "@angular/core": "^4.0.0",
    "@angular/forms": "^4.0.0",
    "@angular/http": "^4.0.0",
    "@angular/platform-browser": "^4.0.0",
    "@angular/platform-browser-dynamic": "^4.0.0",
    "@angular/router": "^4.0.0",
    "core-js": "^2.4.1",
    "rxjs": "^5.1.0",
    "zone.js": "^0.8.4"
},
"devDependencies": {
    "@angular/cli": "1.0.0-rc.1",
    "ts-node": "~2.0.0",
    "tslint": "~4.5.0",
    "typescript": "~2.1.0"
}

二、依赖更改

依赖导入更改:

'angular2/core' => '@angular/core'

'angular2/http' => '@angular/http'

'angular2/router' => '@angular/router'

// 表单相关的

'angular2/commom' => '@angular/forms'

三、新增NgModule

官方说明

Angular 模块能帮你把应用组织成多个内聚的功能块。

Angular 模块是带有 @NgModule 装饰器函数的类。 @NgModule 接收一个元数据对象,该对象告诉 Angular 如何编译和运行模块代码。 它标记出该模块拥有的组件、指令和管道, 并把它们的一部分公开出去,以便外部组件使用它们。 它可以向应用的依赖注入器中添加服务提供商。

具体请参考官方文档

管理公用组件

  • 创建SharedModule管理所有公用组件
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
// 引入公用组件
import {SomeService} from './service/some.service';
import {SomeComponent} from './component/some.component';
import {SomePipe} from './pipe/some.pipe';
import {SomeDirective} from './directive/ng-file-select.directive';

@NgModule({
  imports: [CommonModule, FormsModule],
  declarations: [SomeComponent, SomePipe, SomeDirective],
  exports: [CommonModule, FormsModule, SomeComponent, SomePipe],
  providers: [SomeService]
})
export class SharedModule {}
  • 其他模块只需要引入SharedModule
import {NgModule} from '@angular/core';
// 引入SharedModule
import {SharedModule} from 'shared/shared.module';
// 该模块路由
import {SomeRoutingModule} from './main-routing.module';
// 该模块相关Component
import {SomeComponent} from './main.component';

@NgModule({
  imports: [SharedModule, SomeRoutingModule],
  declarations: [SomeComponent],
  exports: [SomeComponent]
})
export class SomeModule {
}

四、路由相关

变更

拆分和新增了路由模块

  • ActivatedRoute:获取路由信息
  • 路由事件实例,如NavigationEnd表示导航事件变更完毕,等
  • 反正改了挺多的,请自行查询官方API文档…[捂脸]

新增路由模块

路由使用NgModule创建,示例如下:

import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';

import {SomeComponent} from './main.component';
import {ListComponent} from './list.component';
import {DetailComponent} from './detail.component';

const routes: Routes = [ 
  // 这里displayName主要供面包屑使用
  {path: '', component: SomeComponent, data: {displayName: '某个模块'},
  children: [
    {path: 'list', component: ListComponent, data: {displayName: '列表'}},
    {path: 'list', component: DetailComponent, data: {displayName: '详情'}},
    {path: '**', redirectTo: 'list'}
  ]},
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
  providers: []
})
export class SomeRoutingModule {}

路由相关常用

// 监听导航事件变更
// router: Router
router.events.filter(event => event instanceof NavigationEnd).subscribe(event => {});
// 获取路由信息
// activatedRoute: ActivatedRoute
const rootRoute: ActivatedRoute = activatedRoute.root // 获取根路由
const children: ActivatedRoute[] = rootRoute.children; // 获取子路由
// 遍历子路由,获取其params/data/url等
for (const child of children) {
     console.log(child.snapshot.data); // 获取data
     console.log(child.snapshot.params); // 获取params
     console.log(child.snapshot.url, child.snapshot.url[0].path); // 获取url或path信息
}

若要写面包屑功能,可参考该文章Angular2 Breadcrumb using Router

五、表单相关

依赖API更改


// 依赖中某些API更改
// ControlGroup => FormGroup
import {ControlGroup} from 'angular2/commom';
=> import {FormGroup} from '@angular/forms';
// Control => FormControl
import {Control} from 'angular2/commom';
=> import {FormControl} from '@angular/forms';

原使用[ngFormModel]属性

  • 更改表单属性 [ngFormModel] 为 [formGroup]
<form [ngFormModel]="myform" /> => <form [formGroup]="myform" />
  • 同时在module文件需引入FormsModule和ReactiveFormsModule
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
  • 更改表单内input属性[ngFormControl]为formControlName
<input [ngFormControl]="url" /> => <input formControlName="url" />
  • 若要在[ngFormModel]属性的<form>内使用ngModel,需添加
[ngModelOptions]="{standalone: true}"属性
<input name="url" [(ngModel)]="url" [ngModelOptions]="{standalone: true}" />
若要在[ngFormModel]属性的<form>内使用#url="ngForm"来进行验证,需更改验证url.valad为mgform.controls.url.valid
原使用ngForm

更改表单内input属性ngControl="url"为#url="ngModel"
同时需要在该input标签添加name属性
<input ngControl="url" /> => <input #url="ngModel" name="url" />
若不需要表单验证,则不需添加name属性,而添加[ngModelOptions]="{standalone: true}"
<input #url="ngModel" /> => <input #url="ngModel" [ngModelOptions]="{standalone: true}" />
组件封装使用[(ngModel)]

使用时需加上name以及ngDefaultControl两个属性
<date-time-picker [(ngModel)]="start_time" /> 
=> <date-time-picker name="start_time" [(ngModel)]="start_time" ngDefaultControl />

六、其他问题

1. http请求内容带url时后台解析错误

原因:angular(v4.0.0)中封装的http服务对参数standardEncoding编码方法,见node_modules/@angular/http/@angular/http.js文件,导致后台获取图片地址失败。 解决办法:使用encodeURIComponent覆盖standardEncoding编码

/**
 * 覆盖原有的standardEncoding方法,见http.js文件
 */
class MyQueryEncoder extends QueryEncoder {
  encodeKey(k: string): string {
    return encodeURIComponent(k);
  }
  encodeValue(v: string): string {
    return encodeURIComponent(v);
  }
}

2. 组件迁移后,无法正确订阅事件

原因:angular(v4.0.0)中依赖注入,若在不同地方声明provider,则会创建不同的实例。

解决办法:在app根组件声明provider注入ResultHandler服务,则整个app使用同一个实例。

3. 升级angular-cli版本失败

原因:angular-cli版本升级后,对应webpack版本修改了默认的disableHostCheck属性,导致ng serve --port会出现Invalid Host header。 解决办法:回退版本,或者手动更改node_modules里webpack相关配置(可查看nvalid Host header after updating to 1.0.1 #6070)

4. 运行npm run build --prod命令失败

原因:basically the problem is in AOT and Angular analyzer. It analyzes code in all cases whether you wanted to have aot or not. 解决办法:1) -prod => --prod --aot=false 2) -prod => --env=prod(可查看ng build -prod Module not found: Error: Can’t resolve ‘./$$_gendir/app/app.module.ngfactory’ #4551)

PS:运行代码可通过:即时JIT编译器动态引导、使用预编译器( AoT - Ahead-Of-Time )两种方式。进行静态引导.静态方案可以生成更小,启动更快的应用,默认优先使用。但此处因为有些动态计算环境的代码,故编译失败,此处手动关闭。

5. 升级angular(v2.4.0)到(v4.1.1)版本后,左侧导航的状态定位失效

原因:升级后,router和component的hook顺序调整(仅根据个人观察,未经验证),导致组件状态未能在路由事件结束(NavigationEnd)时完成更新。 解决办法:目前在路由事件结束(NavigationEnd)时,手动更新组件状态。

的内嵌样式失效。" class="reference-link" >6. html模版里,在style里使用style="color: {{someValidation ? 'red' : ''}}"的内嵌样式失效。

原因:angular(v4.1.1)中,需使用[ngStyle]属性方式对样式进行设置。 解决办法:1) 更改为[ngStyle]="{'color': someValidation ? 'red' : ''}"2) 更改为[style.color]="someValidation ? 'red' : ''"

7. 在webstorm里,更改文件不能在浏览器中更新输出。

原因:webstorm里面默认启用”safe write”,将保存先存到临时文件。 解决办法:关闭File > Settings... > System Settings > Use "safe write",参见angular-cli issue#5507 。

8. 无法从router里获取RouteParams的API。

原因:angular(v4.1.1)中,使用ActivatedRoute的API获取路由信息。

原代码:


import { RouteParams } from 'angular2/router';
... // 其余代码
    ngOnInit() {
        this.id = parseInt(this._routeParams.get('id'));
        this.needSaveBtn = (this._routeParams.get('action') || '') != 'detail';//查看、编辑、添加
        ... // 其余代码
    }
... // 其余代码

新代码:

import { ActivatedRoute } from '@angular/router';
... // 其余代码
    ngOnInit() {
      this._route.params
        .subscribe((params) => {
          this.id = parseInt(params['id']);
          this.needSaveBtn = (params['action'] || '') != 'detail';//查看、编辑、添加
         ... // 其余代码
        });
    }
... // 其余代码

9. 使用angular-cli后无法自定义webpack的alias, 导致文件引入路径很长,如../../../shared/。

原因:angular-cli内部封装了webpack配置,若手动改动node_modules不方便。 解决办法:查看fix(build): use baseUrl and paths from tsconfig #2470,该issue只针对性调整shared目录,具体可查看相关Commit信息

使用方式:

// 在src/目录下修改tsconfig.app.json
{
  "compilerOptions": {
    ...
    // 添加路径相关
    "baseUrl": ".",
    "paths": {
      "@shared/*": ["app/shared/*"]
    }
    ...
  },
  ...
}

// 在根目录下修改tsconfig.json
// 主要用于编译器IDE检测使用
{
  "compilerOptions": {
    ...
    // 添加路径相关
    "baseUrl": ".",
    "paths": {
      "@shared/*": ["src/app/shared/*"]
    }
    ...
  },
  ...
}

10.升级angular(v4.1.1)版本后,组件迁移状态更新失效

原因:升级后,component的hook顺序调整,导致组件状态未能在component状态更新后完成更新。

解决办法:检测状态变更时,需手动再添加状态更新。

11.升级angular到(v4.1.1)版本后,<iframe>等带动态src等属性触发error

原因:angular2启用安全无害化处理,为防止XSS等攻击,具体可参考官方文档安全。

解决办法:注入DomSanitizer服务可以把一个值标记为可信任的,这里添加了一个叫safeUrl的pipe组件,位于app/shared/pipe/safe-url.main.pipe.ts。 使用方式:<iframe [src]="url | safeUrl">

12.迁移一些文件后,启动app失败,出现Cannot read property 'length' of undefined

原因:有些文件里面带有/// ,若路径不对文件找不到则无法启动。

解决办法:调整文件路径,或者删除这些内容。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏米扑专栏

Python+Selenium2 搭建自动化测试环境

27611
来自专栏腾讯移动品质中心TMQ的专栏

Appium:轻松玩转app+webview混合应用自动化测试

Appium这个听起来既生疏也熟悉的自动化测试工具,比起原生的UiAutomator可能是异常的不起眼,可是却是有自身独当一面的能力,可以完成许多高难度作业,完...

1.5K0
来自专栏星回的实验室

JavaScript中的沙箱机制探秘[二]:iFrame沙箱实现方案详解

在上一篇文中,我们接触了JavaScript中的sandbox的概念,并且就现阶段的一些实现思路做了总结,包括YUI的闭包、iframe的sandbox以及No...

881
来自专栏技术博文

34款Firefox渗透测试插件

工欲善必先利其器,firefox一直是各位渗透师必备的利器,小编这里推荐34款firefox渗透测试辅助插件,其中包含渗透测试、信息收集、代理、加密解密等功能。...

34413
来自专栏云计算教程系列

如何在Ubuntu 14.04中使用NodeJS,SailsJS和DustJS构建SPA(单页应用程序)

Node.js®是一个基于Chrome JavaScript运行时的平台,可轻松构建快速,可扩展的网络应用程序。Node.js使用事件驱动的非阻塞I / O模型...

450
来自专栏進无尽的文章

扒虫篇-Bug日志 Ⅰ

之前在集成调试 AsReader的时候,遇到的bug,是一家日本企业生产的产品,官方文档比较简单而且还不写清楚,表面上看是报的不兼容 64位模拟器的错误,我用...

792
来自专栏技术/开源

开源的API集成测试工具 v0.1.2 - 增强体验

Hitchhiker 是一款开源的 Restful Api 集成测试工具,你可以在轻松部署到本地,和你的team成员一起管理Api。 详细介绍请看: https...

17710
来自专栏惶心 - 技术博客

下载 m3u8 视频流

到现在,非常多的视频网站都是利用 m3u8 格式的特性,把一段视频分成多段,进而增加各类软件下载网页上视频的难度。

6126
来自专栏写代码的海盗

Nodejs课堂笔记—第一课:修改Webstorm的默认主题

    最近小半年一直在忙于研究Docker源码,也在写相关的分析文章。但受限于某些条件不能发布到网上,甚为郁闷。而最近几天,接到新的开发任务,需要使用node...

2555
来自专栏小白安全

Discuz网站通用修改注册会员数和显示在线人数

一.修改在线人数跟会员: 1.找到文件:sourcemoduleforumforum_index.php 2.查找代码: $onlinenum...

2798

扫码关注云+社区