Formula 1 2013 Results | ||||
---|---|---|---|---|
Round | Grand Prix | Team | Grid | Race |
{{race.round}} | {{race.raceName}} | {{race.Results[0].Constructor.name}} | {{race.Results[0].grid}} | {{race.Results[0].position}} |
作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Raoni的BCS和十年的web开发经验见证了他领导和贡献了大量使用RoR的项目, JS, and PHP, among others.
AngularJS 是一个JavaScript MVC框架开发的谷歌,让您建立良好的结构, easily testable, 以及可维护的前端应用程序.
如果你还没有尝试过AngularJS,那你就错过了. 该框架由一个紧密集成的工具集组成,它将帮助您构建良好的结构, 模块化方式的富客户端应用程序——代码更少,灵活性更高.
AngularJS通过提供 directives 这为您的标记添加了功能,并允许您创建强大的动态模板. 你也可以创建自己的指令, 制作满足您需求的可重用组件,并抽象掉所有DOM操作逻辑.
它还实现了双向数据绑定, 无缝连接HTML(视图)和JavaScript对象(模型). In simple terms, 这意味着对模型的任何更新都将立即反映在视图中,而不需要任何DOM操作或事件处理.g., with jQuery).
最后,我喜欢Angular是因为它在服务器通信方面的灵活性. 像大多数JavaScript MVC框架一样, 它允许您使用任何服务器端技术,只要它可以通过RESTful web API为您的应用程序提供服务. 但是Angular也提供服务 on top 它极大地简化了代码,并允许您将API调用抽象为可重用的服务. As a result, 你可以将模型和业务逻辑移到前端,构建与后端无关的web应用程序. 在这篇文章中,我们就这样做,一步一步来.
首先,让我们决定要构建的应用程序的性质. In this guide, 我们希望不要在后台花费太多时间, 所以我们将基于在互联网上很容易获得的数据编写一些东西,比如一个体育动态应用程序!
因为我恰好是赛车和f1的超级粉丝, 我将使用一个汽车运动API服务作为我们的后端. Luckily, the guys at Ergast 是否可以提供一个免费的赛车运动API,这对我们来说是完美的.
让我们用一些样板文件来启动我们的示例应用程序. I recommend the angular-seed 项目,因为它不仅为您提供了一个伟大的骨架引导, 也为单元测试奠定了基础 Karma and Jasmine (we won’t be doing any testing in this demo, so we’ll just leave that stuff aside for now; see Part 2 关于为单元和端到端测试设置项目的更多信息,请参阅本教程).
EDIT (May 2014): 自从我编写了本教程以来 angular-seed 项目经历了一些重大的变化(包括添加 Bower as package manager). 如果您对如何部署项目有任何疑问, 快速浏览一下他们的第一部分 reference guide. In Part 2 of ths tutorial, Bower在其他工具中,将更详细地介绍.
OK, 现在我们已经克隆了存储库并安装了依赖项, 我们的应用程序的骨架是这样的:
Now we can start coding. 因为我们正试图为赛车锦标赛建立一个体育频道, 让我们从最相关的观点开始: the championship table.
假设我们已经在我们的作用域中定义了一个驱动程序列表(请跟着我——我们将到达那里), 并忽略任何CSS(为了可读性), our HTML might look like:
Drivers Championship Standings
{{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}}
{{driver.Constructors[0].name}}
{{driver.points}}
在这个模板中,您将注意到的第一件事是使用表达式(“{{”和“}}”)来返回变量值. In AngularJS development表达式允许您执行一些计算以返回所需的值. 一些有效的表达式是:
{{ 1 + 1 }}
{{ 946757880 | date }}
{{ user.name }}
实际上,表达式是类似javascript的代码片段. 但是,尽管表达式非常强大,但您不应该使用表达式来实现任何高级逻辑. For that, we use directives.
你会注意到的第二件事是 ng-attributes
这在典型的标记中是看不到的. Those are directives.
At a high level, 指令是标记(比如属性), tags, 和类名),告诉AngularJS将给定的行为附加到DOM元素(或对其进行转换), replace it, etc.). 让我们来看看我们已经看过的:
The ng-app
指令负责引导你的应用定义它的作用域. In AngularJS, 你可以在同一个页面上有多个应用程序, 这个指令定义了每个应用开始和结束的位置.
The ng-controller
指令定义了哪个控制器将负责你的视图. In this case, we denote the driversController
,它将提供我们的驱动程序列表(driversList
).
The ng-repeat
指令是最常用的指令之一,用于在遍历集合时定义模板作用域. 在上面的示例中,它为中的每个驱动程序复制表中的一行 driversList
.
当然,如果没有控制器,视图就没有任何用处. Let’s add driversController
to our controllers.js:
angular.module('F1FeederApp.controllers', []).
控制器(' drivercontroller ', function($scope) {
$scope.driversList = [
{
Driver: {
givenName: 'Sebastian',
familyName: 'Vettel'
},
points: 322,
nationality: "German",
Constructors: [
{name: "Red Bull"}
]
},
{
Driver: {
givenName: 'Fernando',
familyName: 'Alonso'
},
points: 207,
nationality: "Spanish",
Constructors: [
{name: "Ferrari"}
]
}
];
});
You may have noticed the $scope
我们作为参数传递给控制器的变量. The $scope
变量应该连接你的控制器和视图. 特别是,它包含将在模板中使用的所有数据. 任何你加进去的东西(比如 driversList
在上面的例子中)将在视图中直接访问. For now, 让我们来处理一个虚拟(静态)数据数组, 稍后我们将用API服务替换它.
Now, add this to app.js:
angular.module('F1FeederApp', [
'F1FeederApp.controllers'
]);
通过这行代码,我们实际初始化了我们的应用,并注册了它所依赖的模块. 我们会回到那个文件(app.js
) later on.
现在,让我们把所有的东西放在一起 index.html
:
F-1 Feeder
Drivers Championship Standings
{{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}}
{{driver.Constructors[0].name}}
{{driver.points}}
模除小错误,你现在可以启动你的应用程序并检查你的(静态)驱动程序列表.
注意:如果你需要帮助调试你的应用程序,并在浏览器中可视化你的模型和作用域, 我建议你去看看那些很棒的东西 Batarang plugin for Chrome.
因为我们已经知道如何在视图中显示控制器的数据, 现在是时候从RESTful服务器实际获取实时数据了.
为了方便与HTTP服务器的通信,AngularJS提供了 $http
and $resource
services. 前者不过是上面的一层 XMLHttpRequest or JSONP,而后者提供了更高层次的抽象. We’ll use $http
.
从控制器中抽象我们的服务器API调用, 让我们创建自己的自定义服务,它将获取数据并充当包装器 $http
by adding this to our services.js
:
angular.module('F1FeederApp.services', []).
factory('ergastAPIservice', function($http) {
var ergastAPI = {};
ergastAPI.getDrivers = function() {
return $http({
method: 'JSONP',
url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
});
}
return ergastAPI;
});
通过前两行代码,我们创建了一个新模块(F1FeederApp.services
),并在该模块内注册服务(ergastAPIservice
). Notice that we pass $http
作为该服务的参数. This tells Angular’s dependency injection 我们的新服务需要的引擎(或 depends on) the $http
service.
以类似的方式,我们需要告诉Angular将我们的新模块包含到我们的应用中. Let’s register it with app.js
,将现有代码替换为:
angular.module('F1FeederApp', [
'F1FeederApp.controllers',
'F1FeederApp.services'
]);
现在,我们需要做的就是调整我们的 controller.js
a bit, include ergastAPIservice
作为一个依赖项,我们就可以开始了:
angular.module('F1FeederApp.controllers', []).
控制器(' drivercontroller ', function($scope, ergastAPIservice) {
$scope.nameFilter = null;
$scope.driversList = [];
ergastAPIservice.getDrivers().Success (function (response)) {
//深入响应以获取相关数据
$scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
});
});
现在重新加载应用程序并查看结果. 注意,我们没有对模板做任何更改,但是我们添加了一个 nameFilter
variable to our scope. 我们来用一下这个变量.
Great! 我们有一个功能控制器. 但它只显示了一个司机列表. 让我们通过实现一个简单的文本搜索输入来添加一些功能,它将过滤我们的列表. 让我们将以下行添加到 index.html
, right below the tag:
We are now making use of the ng-model
directive. 这个指令将我们的文本字段绑定到 $scope.nameFilter
变量,并确保其值始终与输入值保持一致. Now, let’s visit index.并对包含的行做一个小的调整 ng-repeat
directive:
This line tells ng-repeat
在输出数据之前, driversList
数组中存储的值必须对其进行筛选 nameFilter
.
At this point, 双向数据绑定开始生效:每次在搜索字段中输入值时, Angular会立即确保 $scope.nameFilter
我们用新值更新了与它关联的. 由于绑定是双向的,所以时刻 nameFilter
值被更新后,与之关联的第二个指令(i.e., the ng-repeat
)也会获得新的值,并立即更新视图.
重新加载应用程序并查看搜索栏.
注意,这个过滤器将在模型的所有属性上查找关键字, 包括那些我们不用的. 假设我们只想过滤 Driver.givenName
and Driver.familyName
: First, we add to driversController
, right below the $scope.driversList = [];
line:
$scope.searchFilter = function (driver) {
var keyword = new RegExp($scope.nameFilter, 'i');
return !$scope.nameFilter || keyword.test(driver.Driver.givenName) || keyword.test(driver.Driver.familyName);
};
Now, back to index.html
,则更新包含的行 ng-repeat
directive:
再重新加载一次应用程序,现在我们有了一个按名称搜索.
Routes
我们的下一个目标是创建一个司机详细信息页面,让我们点击每个司机并查看他/她的职业生涯详细信息.
First, let’s include the $routeProvider
service (in app.js
),这将有助于我们处理这些变化 application routes. 然后,我们将添加两条这样的路线:一条用于积分榜,另一条用于车手详细信息. Here’s our new app.js
:
angular.module('F1FeederApp', [
'F1FeederApp.services',
'F1FeederApp.controllers',
'ngRoute'
]).
配置('$routeProvider', function($routeProvider) {
$routeProvider.
当("/drivers", {templateUrl: "partials/drivers ..html", controller: " drivercontroller "}).
当("/drivers/:id", {templateUrl: "partials/driver . id"., controller: "driverController"}).
否则({redirectTo: ' /司机'});
}]);
有了这个变化,导航到 http://domain/#/drivers
will load the driversController
寻找要渲染的局部视图 partials/drivers.html
. But wait! 我们还没有局部视图,对吧? 我们也需要创建这些.
Partial Views
AngularJS允许你将路由绑定到特定的控制器和视图.
但首先,我们需要告诉Angular在哪里渲染这些分部视图. For that, we’ll use the ng-view
directive, modifying our index.html
to mirror the following:
F-1 Feeder
Now, 当我们浏览应用程序的路由时, Angular会加载关联的视图,并将其渲染到
tag. 我们所需要做的就是创建一个名为 partials/drivers.html
把我们的冠军表格HTML放在那里. 我们还将利用这个机会将驱动名链接到我们的驱动细节路由:
Drivers Championship Standings
{{$index + 1}}
{{driver.Driver.givenName}} {{driver.Driver.familyName}}
{{driver.Constructors[0].name}}
{{driver.points}}
最后,让我们决定要在详细信息页面中显示什么. 关于司机(e)的所有相关事实的总结怎么样.g.(如出生、国籍)以及一个包含他/她最近成绩的表格? To do that, we add to services.js
:
angular.module('F1FeederApp.services', [])
.factory('ergastAPIservice', function($http) {
var ergastAPI = {};
ergastAPI.getDrivers = function() {
return $http({
method: 'JSONP',
url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
});
}
ergastAPI.getDriverDetails = function(id) {
return $http({
method: 'JSONP',
url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/ driverrankings.json?callback=JSON_CALLBACK'
});
}
ergastAPI.getDriverRaces = function(id) {
return $http({
method: 'JSONP',
url: 'http://ergast.http://api/f1 /2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK'
});
}
return ergastAPI;
});
This time, 我们向服务提供驾驶员的ID,以便检索仅与特定驾驶员相关的信息. Now, we modify controllers.js
:
angular.module('F1FeederApp.controllers', []).
/* Drivers controller */
控制器(' drivercontroller ', function($scope, ergastAPIservice) {
$scope.nameFilter = null;
$scope.driversList = [];
$scope.searchFilter = function (driver) {
var re = new RegExp($scope.nameFilter, 'i');
return !$scope.nameFilter || re.test(driver.Driver.givenName) || re.test(driver.Driver.familyName);
};
ergastAPIservice.getDrivers().Success (function (response)) {
//挖掘响应以获取相关数据
$scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
});
}).
/* Driver controller */
控制器('driverController', function($scope, $routeParams, $ ergastAPIservice) {
$scope.id = $routeParams.id;
$scope.races = [];
$scope.driver = null;
ergastAPIservice.getDriverDetails($scope.id).Success (function (response)) {
$scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0];
});
ergastAPIservice.getDriverRaces($scope.id).Success (function (response)) {
$scope.races = response.MRData.RaceTable.Races;
});
});
这里需要注意的重要一点是我们刚刚注入了 $routeParams
服务到驱动控制器. 该服务将允许我们访问URL参数 :id
, in this case) using $routeParams.id
.
现在我们已经在作用域中拥有了数据,我们只需要剩下的部分视图. Let’s create a file named partials/driver.html
and add:
<- Back to drivers list
Formula 1 2013 Results
Round Grand Prix Team Grid Race
{{race.round}}
{{race.raceName}}
{{race.Results[0].Constructor.name}}
{{race.Results[0].grid}}
{{race.Results[0].position}}
注意到我们现在把 ng-show
directive to good use. 该指令只会在表达式为时显示HTML元素 true
(i.e., neither false
, nor null
). In this case, 只有当驱动对象被控制器加载到作用域中时,角色才会出现.
Finishing Touches
添加一堆CSS并渲染您的页面. 你应该得到这样的结果:
现在,你已经准备好启动你的应用程序,并确保两条路由都能正常工作. 还可以添加静态菜单 index.html
提高用户的导航能力. 可能性是无限的.
EDIT (May 2014): 我收到了许多欧博体育app下载在本教程中构建的代码的可下载版本的请求. 因此,我决定公布它 here (stripped of any CSS). However, I really do not recommend downloading it, 由于本指南包含了您自己构建相同应用程序所需的每一个步骤, 哪种学习方法更有用、更有效.
Conclusion
在教程的这一点上, 我们已经涵盖了编写一个简单应用程序(如f1馈线)所需的所有内容。. 实时演示中的其余每个页面(例如.g., 建设者积分榜, team details, 日历)共享我们在这里回顾的相同的基本结构和概念.
Finally, 请记住,Angular是一个非常强大的框架,就它所提供的一切而言,我们仅仅触及了表面. In Part 2 of this tutorial, 我们将举例说明为什么Angular在同级前端MVC框架中脱颖而出:可测试性. 我们将回顾编写和运行单元测试的过程 Karma,实现与的持续集成 Yeomen, Grunt, and Bower,以及这个奇妙的前端框架的其他优势.
Understanding the basics
What is AngularJS?
AngularJS是一个由Google开发的JavaScript MVC框架,可以让你构建良好的结构, easily testable, 以及可维护的前端应用程序.
Why AngularJS?
AngularJS通过提供向你的标记添加功能的指令来扩展HTML,并允许你创建强大的动态模板. 你也可以创建自己的指令, 制作满足您需求的可重用组件,并抽象掉所有DOM操作逻辑.
就这一主题咨询作者或专家.Schedule a callAbout the author
Raoni的BCS和十年的web开发经验见证了他领导和贡献了大量使用RoR的项目, JS, and PHP, among others.
作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.Years of Experience
16
世界级的文章,每周发一次.
世界级的文章,每周发一次.
Toptal Developers
- Algorithm Developers
- Angular Developers
- AWS Developers
- Azure Developers
- Big Data Architects
- Blockchain Developers
- 商业智能开发人员
- C Developers
- Computer Vision Developers
- Django Developers
- Docker Developers
- Elixir Developers
- Go Engineers
- GraphQL Developers
- Jenkins Developers
- Kotlin Developers
- Kubernetes Experts
- Machine Learning Engineers
- Magento Developers
- .NET Developers
- R Developers
- React Native Developers
- Ruby on Rails Developers
- Salesforce Developers
- SQL Developers
- Sys Admins
- Tableau Developers
- Unreal Engine Developers
- Xamarin Developers
- 查看更多自由开发者
Join the Toptal® community.
\n \n \n \n \n\n