本文由Dan Prince和Michaela Lehr进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
在AngularJS的每个新发行版中,开发团队都试图弥合AngularJS 1.x和2之间的差距。随着AngularJS 1.5的发行,开发人员将能够编写结构类似于AngularJS 2.0的应用程序。
在本教程中,我们将在AngularJS 1.4中创建一个grid 指令 。 然后,我们将逐步完成将其升级到1.5的步骤,然后研究如何将其转换为可与2.0版一起使用。
入门
首先创建一个名为AngularMigrateApp
的项目目录。 在此文件夹中,创建一个名为index.html
的HTML页面。 该页面应如下所示:
<!DOCTYPE html>
<html lang="en" ng-app="myApp" class="no-js">
<head>
<title>My AngularJS App</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<script src="https://code.angularjs.org/1.4.10/angular.js"></script>
</body>
</html>
除了Angular框架外,我们还将利用Bootstrap设计指令布局。 我们包括直接来自CDN的这两个文件。
创建网格指令
让我们创建一个简单的网格指令来显示JSON数组。 我们将从创建AngularJS模块开始。
angular.module('myApp', [])
.constant('employees', [{
firstName: 'Rima',
lastName: 'George',
location: 'San Francisco'
}, {
firstName: 'Shaun',
lastName: 'John',
location: 'Germany'
}, {
firstName: 'Rahul',
lastName: 'Kurup',
location: 'Bangalore'
}, {
firstName: 'Samson',
lastName: 'Davis',
location: 'Canada'
}, {
firstName: 'Shilpa',
lastName: 'Agarwal',
location: 'Noida'
}])
.controller('HomeCtrl', ['$scope', 'employees', function($scope, employees) {
$scope.employees = employees;
}])
我们定义了一个名为employees
的常量,其中包含示例数据数组。 然后,我们将此数组注入HomeCtrl
,并使其在控制器的作用域中可用。
让我们创建一个名为myGrid
的指令,该指令将用于显示上述JSON数组。
.directive('myGrid', function() {
return {
}
})
我们想通过标签名称使用指令,如下所示:
<my-grid></my-grid>
因此,我们将添加限制选项以指定以下内容:
.directive('myGrid', function() {
return {
restrict: 'E'
}
})
接下来,我们要将employees
数据从视图传递到指令。 因此,我们将其添加为绑定:
.directive('myGrid', function() {
return {
restrict: 'E',
scope: {
info: '=info'
}
}
})
现在,我们可以将employees
数据作为属性传递给指令:
<my-grid info="employees"></my-grid>
最后但并非最不重要的一点是,我们需要一个HTML模板来显示数据:
.directive('myGrid', function() {
return {
restrict: 'E',
scope: {
info: '=info'
},
templateUrl : '/directiveGrid.html'
}
})
在index.html
正文中添加以下HTML模板脚本。
<script type="text/ng-template" id="/directiveGrid.html">
<div class="panel panel-primary">
<div class="panel-heading">Site Point Directive Grid</div>
<table class="table">
<thead>
<tr>
<th>FirstName</th>
<th>Last Name</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in info">
<td>{{ employee.firstName }}</td>
<td>{{ employee.lastName }}</td>
<td>{{ employee.location }}</td>
</tr>
</tbody>
</table>
</div>
</script>
如您在上面的代码中看到的,我们正在遍历info
属性并显示employees列表中的每个项目。
让我们在index.html
使用myGrid
指令。 添加以下代码:
<div ng-controller="HomeCtrl">
<my-grid info="employees"></my-grid>
</div>
我们指定了HomeCtrl
控制器,并在其中使用了指令。 保存更改并浏览到index.html
页面。 这是运行中的数据网格的演示:
请参阅CodePen上的SitePoint ( @SitePoint )提供的Pen AngularJS 1.4演示 。
升级到1.5
到目前为止,我们已经使用1.4版创建了AngularJS指令,并且运行良好。 现在,让我们尝试在AngularJS 1.5中使用相同的代码,看看是否有任何问题。
让我们用指向版本1.5的CDN链接替换现有的脚本引用。 如果您尝试刷新页面,则所有内容都应继续正常运行。 在1.x系列的新发行版中,该框架通过使用components ,更接近AngularJS 2.0的工作方式,并且我们可以在代码中利用这一点,从而使最终过渡到2.0版变得更加容易。
在AngularJS 1.5中,组件是指令的语法糖,它负责默认值并具有更简单的配置。 它们应该是替代产品,特别是对于那些将来想要升级的用户。
使用AngularJS时,开发人员通常倾向于使用基于控制器的方法,但这会在应用程序开始增长时产生许多问题。 基于控制器和视图的方法会导致重复的ng-controller / view,但是基于组件的方法通过创建无需重复代码即可组成更大组件的组件来解决此问题。
让我们尝试利用新的组件指令帮助器方法并修改我们现有的代码。 我们将从创建一个组件开始:
.component('myDataComp', {});
与使用函数的指令方法不同,组件方法使用对象。 我们将使用不同的模板传递与指令中相同的对象。 这是HTML模板:
<script type="text/ng-template" id="/componentGrid.html">
<div class="panel panel-primary">
<div class="panel-heading">Site Point Directive Grid</div>
<table class="table">
<thead>
<tr>
<th>FirstName</th>
<th>Last Name</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in info">
<td>{{ employee.firstName }}</td>
<td>{{ employee.lastName }}</td>
<td>{{ employee.location }}</td>
</tr>
</tbody>
</table>
</div>
</script>
这是修改后的组件代码:
.component('myComp', {
restrict: 'E',
scope: {
info: '=info'
},
templateUrl : '/componentGrid.html'
});
如以上代码所示,我们已经传递了旧指令中的所有选项。
在index.html
页面中创建一个名为myComp
的组件。
<div ng-controller="HomeCtrl">
<my-grid info="employees"></my-grid>
<my-comp info="employees"></my-comp>
</div>
保存更改并刷新页面,您应该能够看到没有显示数据,但在浏览器控制台中也没有错误。
如果我们看一下组件和官方网站上的指令之间的比较表,我们可以看到scope
始终是在组件中隔离的。
因此,我们需要使用bindings选项将数据绑定到控制器。 由于组件仅限于元素,因此不再需要restrict
选项。
这是修改后的代码:
.component('myComp', {
bindings: {
info: '=info'
},
templateUrl : '/componentGrid.html'
});
绑定info
将绑定到控制器。 控制器的默认别名为$ctrl
,在模板内部,我们将使用它来访问info
属性:
<script type="text/ng-template" id="/componentGrid.html">
<div class="panel panel-primary">
<div class="panel-heading">Site Point Component Grid</div>
<table class="table">
<thead>
<tr>
<th>FirstName</th>
<th>Last Name</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in $ctrl.info">
<td>{{ employee.firstName }}</td>
<td>{{ employee.lastName }}</td>
<td>{{ employee.location }}</td>
</tr>
</tbody>
</table>
</div>
</script>
现在,如果刷新页面,您应该能够查看使用myComp
组件显示的数据。
请参阅CodePen上的SitePoint ( @SitePoint )提供的Pen AngularJS 1.5演示 。
升级到2.0
注意: AngularJS 2.0仍处于beta中。 我们使用的版本是Angular2.0.0-beta.8 。
让我们用CDN中指向版本2.0的链接替换我们应用程序中现有的AngularJS 版本 ,看看是否有任何中断:
<script src="https://code.angularjs.org/2.0.0-beta.8/angular2.js"></script>
刷新页面后,页面上没有任何显示,如果检查浏览器控制台,我们也会看到一些错误。
如您所见,我们的组件代码在Angular 2.0上无法正常工作!
让我们从头开始,看看新版本是如何工作的,然后我们将尝试移植我们的组件。
尽管可以通过将框架包含一个脚本标签来开始使用Angular 1.x,但是Angular 2.0的情况已经改变。 我们需要几个其他的库才能运行。 虽然可以通过脚本标签分别加载这些文件以进行开发,但它们应作为生产过程的一部分捆绑在一起。
如果我们看一下官方的快速入门指南 ,我们可以看到我们将需要其他一些库和开发依赖项才能开始使用2.0。
让我们创建一个名为AngularJS2.0Component
的文件夹,并如下创建package.json
文件:
{
"name": "angular2-quickstart",
"version": "1.0.0",
"scripts": {
"start": "npm run lite",
"lite": "lite-server"
},
"license": "ISC",
"dependencies": {
"bootstrap": "^3.3.6",
"angular2": "2.0.0-beta.8",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2",
"zone.js": "0.5.15"
},
"devDependencies": {
"concurrently": "^2.0.0",
"lite-server": "^2.1.0"
}
}
上面的文件显示了AngularJS 2.0应用程序所需的所有依赖项。 保存更改并使用npm安装所需的依赖项:
npm install
创建一个名为app
的子文件夹,并在内部使用以下代码创建一个名为app.component.js
的文件:
(function(app) {
app.AppComponent =
ng.core.Component({
selector: 'my-comp',
templateUrl: 'grid.html'
})
.Class({
constructor: function() {
this.employees = [{
firstName: 'Rima',
lastName: 'George',
location: 'San Francisco'
}, {
firstName: 'Shaun',
lastName: 'John',
location: 'Germany'
}, {
firstName: 'Rahul',
lastName: 'Kurup',
location: 'Bangalore'
}, {
firstName: 'Samson',
lastName: 'Davis',
location: 'Canada'
}, {
firstName: 'Shilpa',
lastName: 'Agarwal',
location: 'Noida'
}];
}
});
})(window.app || (window.app = {}));
在上面的代码中,我们使用Angular核心名称空间 ng.core
创建组件。 我们为组件定义了一个选择器,即my-comp
。 我们使用与应用程序模板相同的HTML grid.html
。 我们已经在组件的构造函数中定义了employees
对象。
创建一个名为main.js
的文件,并粘贴以下代码:
(function(app) {
document.addEventListener('DOMContentLoaded', function() {
ng.platform.browser.bootstrap(app.AppComponent);
});
})(window.app || (window.app = {}));
这告诉Angular加载我们刚刚创建的组件。
接下来,在app文件夹外部创建一个名为index.html
的文件,并粘贴以下代码:
<html>
<head>
<title>Angular Component</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" type="text/css" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<!-- 1. Load libraries -->
<!-- IE required polyfill -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script>
<script src="node_modules/angular2/bundles/angular2-all.umd.js"></script>
<!-- 2. Load our 'modules' -->
<script src='app/app.component.js'></script>
<script src='app/main.js'></script>
</head>
<!-- 3. Display the application -->
<body>
<my-comp>Loading...</my-comp>
</body>
</html>
上面的index.html
页面是AngularJS 2.0应用程序的入门模板。 我们已经包含了所有必需的依赖项,并且在body标签中使用了我们的组件。
保存更改并使用npm start
启动服务器。 此命令运行名为lite-server
的本地开发lite-server
,该lite-server
在浏览器中加载index.html
。
但是仍然没有显示数据!
在AngularJS 2.0中,循环的语法有些不同。 修改grid.html
的循环部分,如下所示:
<tr *ngFor="#employee of employees">
保存更改并重新启动服务器,您应该能够看到应用程序中显示的员工数据。
包起来
组件是AngularJS 2.0的主要组成部分,应该说它是基于组件的框架。 在1.x系列的每个新发行版中,我们都越来越接近使用2.0版开发应用程序的方式。
在本教程中,我们使用框架的版本1.4创建了AngularJS指令。 我们对指令进行了重构,以利用1.5版的组件语法。 最后,我们将其升级为可与Angular 2.0版一起使用。
要更深入地了解如何迁移AngularJS应用,请考虑阅读官方迁移指南 。 Angular 2代码也可以用TypeScript和Dart编写,如果您有兴趣,我建议阅读分别在TypeScript或Dart中使用AngularJS 2入门的官方指南。
在下面的评论中分享您的想法和建议!
From: https://www.sitepoint.com/upgrade-to-angular-components/