从 Angular 1 升级到 Angular 2 需要准备的步骤
Posted 前端大全
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从 Angular 1 升级到 Angular 2 需要准备的步骤相关的知识,希望对你有一定的参考价值。
原文:Oren Farhi
译文:伯乐在线 - 段昕理
链接:http://web.jobbole.com/86930/
我最近在试玩 Angular 2。刚开始感觉很奇怪,和我们钟爱的第 1 版完全不同。第 1 版是用 ES5 标准的纯 javascript 编写,而第 2 版采用了 typescript 和 es 2015。不过,你已经可以采取一些步骤,让你的 Angular 1 代码(或用 Angular 1 创建的新项目)更加接近 Angular 2。
我为什么要为 Angular 1 迁移到 Angular 2 做准备
首先,当时机成熟了,你打算用 Angular 2 作为框架时,肯定想让代码迁移更容易些。目前,Angular 小组已经提供了一些迁移策略,你可以混合使用 Angular 1 和 Angular 2 组件,但目标是要将代码库统一,最终只使用一个框架。
其次,在 Angular 2 中更多的是写纯 javascript,然后才是使用专有的框架代码。
再次,社区和浏览器厂商将逐步拥抱 Ecmascript 的最新标准,所以,坚持使用标准编码,尽可能让代码库可复用,而不管选择的框架是什么。
迁移到 Angular 2 的步骤
采取这些策略可以让你的代码更加接近 Angular 2,使转换变得容易。
1. 开始用 Ecmascript 2015
Angular 2 使用 Typescript 编写,Typescript 是 Ecmascript 2015 的超集,带有更多的特性。不过,如果你不喜欢 Typescript, 也可以只用 Ecmascript 2015 编写 angular 2。 目前,代码最终都会编译成 Ecmascript 5。所以实际上你也可以用 Ecmascript 5 来编写 Angular 2。
但是,在我看来,使用 Ecmascript 2015 的新特性,可以减少代码量(有些时候…)、增强代码可读性、用上令人兴奋的特性,如解构。
如果想使用 Ecmascript 2015 的特性,你需要一个转换器来编译代码。目前最流行的转换器是 babel。babel 在很多流行的构建脚本中都可以配置,如 gulp、webpack、browserify 及其它。
// 对象属性增强
var exports = {
search: search,
setType: setType,
setDuration: setDuration
};
// 可以写成这样
var exports = {
search,
setType,
setDuration
};
/////////////
// 使用“胖箭头” => 可以简化代码并增强可读性
var videoIds = response.data.items.map(function(video){
return video.id[idPropertyName[activeType]];
}).join(',');
// 使用了胖箭头符号
var videoIds = response.data.items.map((video) => {
return video.id[idPropertyName[activeType]];
}).join(',');
2. 使用 “angular.service” 替换 “angular.factory”
使用 Ecmascript 2015 意味着我们可以用新的 “class” 关键字来创建新对象甚至扩展其它对象。我曾经写过,比起继承我更热衷于组合,所以我看不出用 “extend” 实现继承有什么用处,不过通过 class 的特性的确可以为创建对象增加好用的语法糖(简化代码)。
在 angular 1 中的 “service” 和 “factory” 的区别是实例化方法:
“service” 使用 “new” 关键字调用(仅一次)
“factory” 使用普通函数调用 — 不需要 “new” 关键字。
在 Angular 2 中,Services 使用了 Ecmascript 2015 类编写。这会导致你需要将 Angular 1 代码中的 factories 转化成 services,并且使用 “class” 替代 function。
例如在我的开源项目-Echoes Player 中,我使用了“class” 和 Angular“service” 编写 youtube api 服务(我以前用的是 factory):
(function() {
'use strict';
/* @ngInject */
class YoutubePlayerApi {
/* @ngInject */
constructor ($window, $q) {
/*jshint validthis: true */
this.deferred = $q.defer();
//当 API 准备好时,Youtube 回调
$window.onYouTubeIframeAPIReady = () => {
this.deferred.resolve()
};
}
// 注入 YouTube 的 iFrame API
load () {
let validProtocols = ['http:', 'https:'];
let url = '//www.youtube.com/iframe_api';
// 我们愿意使用相关的 url 协议,但为避免协议不可用,还是回退到 ‘http:’
if (validProtocols.indexOf(window.location.protocol) < 0) {
url = 'http:' + url;
}
let tag = document.createElement('script');
tag.src = url;
let firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
return this.deferred.promise;
}
}
angular
.module('youtube.player')
.service('YoutubePlayerApi', YoutubePlayerApi);
})();
3. 编写 Controllers 时使用 “Class” 替换 “function”
这一步和上一步多少有些相似。Angular 1 中的 Controllers 总是不停被重建(或 “新建”)- 因为它们不是单例。
Angular 2 几乎不用 controllers。
反之,Angular 2 是基于组件的。每个组件都有一个简单的类(包含少量 es7 注解)来控制。如果你的 Angular 1 代码是用 web 组件方式来编写的,那么很可能每个指令(directive)都对应一个 controller 函数来控制。
有个很重的点必须意识到 - 指令的概念在 Angular 2 中更加简单:
使用了元素选择器的指令都是组件。
剩下的都是指令。
Angular 2 仍然会在内部初始化 services 和 controllers,不要自己去初始化,因为那样会导致代码很难测试。不过 Angular 2 还是易于测试并对 TDD (测试驱动开发) 和 BDD(行为驱动开发)友好。我还写过一篇文章,内容是讲为什么应当封装 “new” 关键字,从而写出更容易测试的代码。
例如把 controller 写成类,会使代码迁移到 angular 2 组件变得非常容易:
class DurationCtrl {
/* @ngInject */
constructor (YoutubeSearch) {
this.YoutubeSearch = YoutubeSearch;
this.durations = [
'Any',
'Short (less then 4 minutes)',
'Medium (4-20 minutes)',
'Long (longer than 20 minutes)'
];
this.durationsMap = [
'',
'short',
'medium',
'long'
];
}
onDurationChange (duration, index) {
this.YoutubeSearch.setType(this.YoutubeSearch.types.VIDEO);
this.YoutubeSearch.setDuration(this.durationsMap[index]);
this.YoutubeSearch.search();
}
}
angular
.module('echoes')
.controller('DurationCtrl', DurationCtrl);
4. 使用指令封装代码
在这一步,你需要重新思考代码,并且使用更好的架构。从 组件(components)/指令(directives) 的角度开始思考。千万不要在 index.html 或任何未关联指令的模板中编写任何 Angular 代码。例如:如果你在一段描述个人资料卡片的代码中使用了 ng-repeat, 你可以创建一个指令,“<person-profile-card>” 或者 “<profile-cards>” (作为一个列表)。
<div ng-repeat="person in vm.persons">
<img ng-src="person.thumb">
<h3>{{:: person.name }}</h3>
<aside>{{:: person.moto }}</aside>
<p>
{{:: person.description }}
</p>
</div>
<!-- 可以转换成一个组件 -->
<div ng-repeat="person in vm.persons">
<person-profile-card model="person"></person-profile-card>
</div>
<!-- 可以成为另一个列表组件 -->
<profile-cards items="vm.persons"></profile-cards>
在即将推出的 Angular 1.5 版本里,你可以使用 ”angular.component“ 定义来创建组件,使得语法( 出自 todd motto 之手)比指令(directive) 更优美。
记住,组件搭配组件(或指令) 就是 Angular 2 的全部,从这个角度思考,将有助于你更好的重新组织代码,也更容易使用 Angular 2。
5. 使用 Angular2to1,ng-upgrade 或其它方法
Angular 2 采用了一个简单漂亮的语法来定义组件(指令)。为了在 es5 代码中体验 Angular 2 的组件语法,我创建了一个 npm 模块 “angular2to1”。示例,你可以在 Angular 1 应用中使用 Angular 2 的 es5 标准语法来定义一个指令:
var myApp = ng
.Component({
selector: 'youtube-videos'
providers: [
'core.services'
],
bindings: {
videos: '@'
}
})
.View({
templateUrl: 'app/youtube-videos/youtube-videos.tpl.html'
})
.Class({
constructor: 'YoutubeVideosCtrl'
})
这和定义一个 Angular 1 指令等效:
angular
.module('youtube-videos', [
'core.services'
])
.directive('youtubeVideos', youtubeVideos);
/* @ngInject */
function youtubeVideos () {
var directive = {
controller: 'YoutubeVideosCtrl',
controllerAs: 'vm',
restrict: 'E',
replace: true,
template: 'app/youtube-videos/youtube-videos.tpl.html',
bindToController: true,
scope: {
videos: '@'
}
};
return directive;
}
有大量的选项可供使用。
ng-upgraders 是一个代码仓库,包含了 Angular 2 升级策略的资源链接。里面有一些有趣的项目,有的项目提供了在 Angular 1 中使用 Angular 2 的 typescript 注解及 Ecmascript 2015 的可能性,这样几乎可以完全用 Angular 2 的语法来写 Angular 1 了。
另外,有很多在 Angular 1 中使用 Ecmascript 2015 的解决方案,无论是从软件架构还是 Angular 推荐架构的角度来看,都坚持了最佳实践和严格准则。
我比较喜欢的一个项目是: NG6-Starter , 项目包含使用 Ecmascrpipt 2015 编写 Angular 1 应用的骨架代码,组件生成器,测试配置和更多内容。
6. (彩蛋)使用模块加载器 system.js、webpack、browserify 或其它工具
所有 Angular 2 例子都依赖于 System.js 库的组件懒加载机制。System.js 既允许我们使用懒加载,也可以编译成压缩好的单一文件用于生产环境。这样你就可以在不同的文件中编写组件(components)和服务(services),不管构建还是开发,都使用构建脚本来解决依赖关系。
In addition, if you rather use gulp.js, webpack or browserify – that’s a no brainer and can be easily configured and integrated.
另外,如果你就是喜欢用 gulp.js、webpack 或 browserify - 完全没理由。没关系,配置和移植都很简单。
总结
我倾向于遵守标准。我认为 Ecmascript 2015 最终会成为了 javascript 语言下一代正式标准,所以,有理由去使用它(我之前也写过)并且拥抱变化。
如果其它的框架、平台和库拥抱了 Ecmascript 2015 标准 ,所有人都会受益。大家可以用更灵活的方式编码,同时在不同的库和项目中共享代码。
译者简介 ( )
段昕理:因为iPod而喜欢上苹果的一系列产品,非常认同他们追求极致的精神。工作之余,喜欢前端的开源项目,Github(https://github.com/sandywalker)
【今日微信公号推荐↓】
更多推荐请看《》
以上是关于从 Angular 1 升级到 Angular 2 需要准备的步骤的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Angular 4 更新/升级到 Angular 5+
Angular 从 1.6.6 升级到 6 时出现 $Injector 错误
从 Angular 9 升级到 Angular 10 时遇到问题
从 Angular js 升级到 Angular 8 的指令