使用 Giphy API 构建一个搜索 GIF 的 Ionic 应用





5.00/5 (1投票)
这篇博客文章涵盖了我们在第一次 Ionic 框架见面会(位于 Čakovec)中学到的内容。
上周,我在 Čakovec 举办了第一次 Ionic 框架见面会。在此,我要感谢 TICM 的孵化和教育负责人 Goran Levačić,感谢他为我们提供了本次见面会的场地。
如果您对未来的活动感兴趣,请务必查看 Meetup 页面 并加入那里的讨论。
会议内容是什么?
首先,我们向那些还没有设置好的用户展示了如何设置 Ionic 框架环境,然后我们一步一步地讲解了一个典型的应用程序。
您可以在 这里 查看第一次见面会的反应,下面有一些照片。此外,TICM 还在 他们的网站 上发布了一篇关于此事的博客文章,如果您想看的话可以去看看(注意:只有克罗地亚语版本)。
演示应用
我们创建了一个简单的应用程序,通过使用 Giphy API 来搜索(并显示)来自 Giphy 网站的 GIF。如今,大多数应用程序都属于这一类;你有一个‘某处’的服务,你在你的应用程序中调用它并显示它的数据。遵循同样的原理,你可以创建一个用于 YouTube、IMDB 等应用程序。
该应用程序的源代码在 Github 上,您也可以 在线试用。
对于那些已经非常熟悉 Ionic 的朋友来说,下面的节奏可能会有点慢。如果是这样,您只需要看看 源代码。
项目启动
首先,让我们使用以下命令启动一个新的 Ionic 项目(从终端执行)
ionic start giphyApp
命令完成后,进入新目录
cd giphyApp
仅为测试目的,让我们运行该应用程序以查看一切是否正常
ionic serve --lab
您应该会看到类似这样的内容
--lab
开关将为您提供一个漂亮的并排视图,展示应用程序在 iOS 和 Android 设备上的外观。
文件夹结构
现在,在您的编辑器中打开此文件夹,您应该会看到类似这样的内容(我使用的是 Sublime Text 3)
在开发 Ionic 应用程序时,您将花费大部分时间在 www 文件夹中。
这里简要介绍一下我们拥有的其他文件夹和文件
- hooks – 包含所谓的 Cordova hooks,它们在 Cordova 构建项目时执行一些代码。根据我的经验,我还没有设置过这个。
- platforms – 包含构建项目后的平台特定文件
- plugins – 包含已添加(或将要添加)到项目中的 Cordova 插件
- scss – 包含 SASS 文件
- Bower 是一个前端包管理器,允许您搜索、安装和更新前端库。您可以在这个 全面的教程 中了解更多。Bower 保存已下载的模块,这些模块在
.bowerrc
文件中定义 - config.xml – Cordova 配置文件
- gulpfile.js – Gulp 配置文件。您可以在这个 入门教程 中了解更多,简而言之;Gulp 是一个所谓的 JavaScript 任务运行器,它有助于处理诸如最小化、混淆、运行单元测试等任务。
- ionic.project – Ionic.io 配置文件
- package.json – 包含有关此项目所需的 Node.js 包的信息
- .gitignore – 定义在推送到 Github 时要忽略的文件
- README.md – 以 Markdown 格式编写的项目信息文档,在您的 Github 项目上自动显示为登陆页面
开始编写代码
好了,蝙蝠侠,理论够多了,让我们来写点代码!
首先,让我们尝试更改第一个选项卡上的一些文本。
当然,但我们怎么知道第一个选项卡定义在哪个文件中呢?
嗯,和所有应用程序一样,让我们开始搜索 index.html。
出于参考,该文件的内容如下所示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,
user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and
remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
</head>
<body ng-app="starter">
<!--
The nav bar that will be updated as we navigate between views.
-->
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<!--
The views will be rendered in the <ion-nav-view> directive below
Templates are in the /templates folder (but you could also
have templates inline in this html file if you'd like).
-->
<ion-nav-view></ion-nav-view>
</body>
</html>
我们看到一个简单的 HTML 文件,其 head
部分包含一些 meta
标签,然后我们导入一些 CSS,最后是一些 js
文件。
在 body
标签中,我们看到它附加了 ng-app="starter"
属性,这告诉我们,在某个 JavaScript 文件中,有一个名为 starter
的模块。
如果我们查看 js 文件夹中的 JavaScript 文件,我们会在 app.js 文件中找到这个 starter
模块。
好的,当然,这都很好,但我们仍然不知道要更改哪个文件!
嗯,如果我们查看 templates 文件夹(当然,您编辑器的搜索功能在这种情况下非常有用;)),我们会看到 tabs-dash.html 文件包含文本 Welcome to Ionic。
现在,删除此文件中的所有代码,除了 h2
,然后写一些类似 Welcome to GiphySearch 的内容。同时,将文本 Dashboard
更改为 GiphySearch
。
仅供参考,tab-dash.html 文件中的内容现在应该是这样的
<h2>Welcome to GiphySearch</h2>
选项卡文本
目前,您应该看到一个屏幕,看起来像这样
这些选项卡并不完全代表我们想要的内容,对吧?
当然,但我们会在哪里改变呢?
嗯,如果您打开 templates/tabs.html 文件,您会看到在哪里可以进行此类更改。所以,将 title
更改为 Home
。
瞧!现在您有了一个名为 Home
的选项卡。
图标
但是,这里的图标有点‘不对劲’,您不觉得吗?
看看 HTML
我们可以看到一些有趣的属性,如 icon-off
和 icon-on
。
是的,在这里您可以定义我们的图标外观。
很好,但是,在哪里可以找到我可以放在这里的确切类名呢?
输入 Ionic 图标
按名称搜索任何您想要的图标,单击它,复制字符串,然后将其放入您的 icon-on
和 icon-off
属性中。
在我们的例子中,我们将使用
<ion-tab title="Home" icon-off="ion-ios-home-outline" icon-on="ion-ios-home" href="#/tab/dash">
按钮
诚然,我们可以直接点击选项卡并在它们之间切换,但既然我们在这里构建一个企业级 xD 应用程序,让我们在 tab-dash.html 文件中添加一个新按钮
<a class="button button-block button-royal">Go to search</a>
如果您想知道这些类名是从哪里来的,您可以查看他们(相当不错的)文档 中的各种按钮。
ui-sref
是 Angular 的 UI Router 的一部分,它基本上设置了点击此按钮后将带我们到的链接。
此时,您应该看到一个屏幕,看起来像这样
并且点击按钮后,应该会显示第二个名为 Chats
的选项卡。
更多选项卡修改
好的,没问题,所以我们点击按钮,它显示 Chats
选项卡。大不了。但我们不想要 Chats 选项卡!我们正在创建一个 Search
应用!
好吧,伙计,放慢点喝咖啡。我们马上就来处理这个问题。
因此,利用之前的知识,我们打开 templates/tab-chats.html,删除 ion-content
标签之间的所有内容,并将标题更改为 Search
。
我们也不喜欢选项卡上的图标和文本,所以让我们进入 templates/tabs.html 文件,并将 Chats 选项卡的定义更改为
<!-- Search Tab -->
<ion-tab title="Search" icon-off="ion-ios-search"
icon-on="ion-ios-search-strong" href="#/tab/search">
<ion-nav-view name="tab-search"></ion-nav-view>
</ion-tab>
我们做了什么?我们只是将 Chats
文本改成了 Search
。但是,我们也为图标添加了不同的类(同样,使用了前面解释的 Ionic 图标)。
这没问题,但如果我们很讲究,并且我们不想要 tab-chats.html,而是想要 tab-search.html。没问题,只需重命名文件即可。
路由 66
但是,现在我们遇到了一个问题。我们第一个选项卡上的按钮不再起作用了。这是因为我们重命名了文件,所以我们需要设置正确的引用。我们在 app.js 文件中进行此操作。只需在该文件中搜索以下代码
.state('tab.chats', {
url: '/chats',
views: {
'tab-chats': {
templateUrl: 'templates/tab-chats.html',
controller: 'ChatsCtrl'
}
}
})
并将其更改为
.state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'ChatsCtrl'
}
}
})
好吧,夏洛克,如果我点击 Search
选项卡,现在就可以工作了,但如果我点击第一个选项卡上的按钮,它就不起作用了!?
是的,没错,这是因为我们设置了错误的 URL。现在将其设置为
<a class="button button-block button-royal">Go to search</a>
瞧,我们现在有一个工作正常的第一个选项卡按钮,并且有一个漂亮、空白、随时准备变得出色的 Search
页面
搜索选项卡大师
所以,我们现在有一个空白屏幕,此时,我们问自己
酷,我们在这里想要什么?
嗯,既然这是一个搜索应用,您觉得一个输入框怎么样?太好了。但是等等!在你开始输入那些 input
标签之前,让我们先查看 Ionic 文档 并稍微滚动一下 Forms
部分。
我个人喜欢 这个,所以让我们将以下代码复制到我们的 tab-search.html 文件中(放在 ion-content
标签内)
<div class="list list-inset"><label class="item item-input">
<i class="icon ion-search placeholder-icon"></i>
<input type="text" placeholder="Search" />
</label></div>
好的,我们现在已经进入状态了,所以我们也来添加一个按钮(放在有 list
类的 div
中)
<a class="button button-block button-royal">Search</a>
供参考,您的 tab-search.html 现在应该具有完全相同的内容
<div class="list list-inset"><label class="item item-input">
<i class="icon ion-search placeholder-icon"></i>
<input type="text" placeholder="Search" />
</label><a class="button button-block button-royal">Search</a>
</div>
它看起来应该像这样
搜索选项卡操作
这一切现在都很好,但现在我们可能会想,当点击这个按钮时,应该发生一些事情,对吧?调用某个函数怎么样?太好了,我们现在就来写吧!
在此按钮上,添加新的 ng-click
属性,它告诉 Angular 一旦点击此按钮,就调用作为属性值编写的函数。好吧,当然,这里有很多废话,代码看起来是这样的
<a class="button button-block button-royal">Search</a>
用通俗的英语来说;一旦按钮被点击,performSearch
函数将被调用。
但是,您又说,如果您点击按钮,什么都不会发生!?嗯,那是因为任何地方都没有定义 performSearch
函数。我们现在就来做。
目前所有控制器都定义在 controllers.js 文件中。但是,您怎么知道要更改哪个控制器呢?嗯,如果您查看 app.js 文件中的路由定义,您会看到我们之前将 search
选项卡更改为
.state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'ChatsCtrl'
}
}
})
所以,答案是:我们需要在 controllers.js 文件中更改 ChatsCtrl
控制器。但是,我们很讲究,还记得吗?所以我们不想要 ChatsCtrl
,而是想要 SearchCtrl
。没问题,只需将上面的列表中的行更改为
controller: SearchCtrl
控制器
在 controllers.js 文件中,完全删除 ChatsCtrl
控制器的代码,而是编写
.controller('SearchCtrl', function($scope) {
console.log("Hello from the Search controller");
})
供参考,整个 controllers.js 文件现在应该包含
angular.module('starter.controllers', [])
.controller('DashCtrl', function($scope) {})
.controller('SearchCtrl', function($scope) {
console.log("Hello from the Search controller");
})
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
$scope.chat = Chats.get($stateParams.chatId);
})
.controller('AccountCtrl', function($scope) {
$scope.settings = {
enableFriends: true
};
});
现在,当我们加载应用程序并转到 Search 选项卡时,我们将在 DevTools Console 窗口中看到以下消息(这是在 Chrome 浏览器中,但我相信您知道如何在您使用的浏览器中使用它,对吧?)
添加函数
我们正在向浏览器控制台输出一些内容,但点击按钮时仍然没有任何反应。要解决此问题,请将以下代码添加到 SearchCtrl
控制器中
scope.performSearch = function (){
console.log("button click");
};
当您点击按钮时,您的浏览器控制台应该看起来像这样
哦,天哪,您说这会很慢,但这就像以 0.25 倍速观看视频。是的,我也爱您。🙂
当点击按钮时,我们现在想做什么?嗯,这时,我们‘以某种方式’将用户在输入框中输入的内容输出到控制台将是合乎逻辑的。这是最简单的方法
将此代码输入 SearchCtrl
控制器
$scope.search = {}
$scope.search.term = 'cats';
现在,在 tab-search.html 文件中,将输入更改为
<input type="text" placeholder="Search" />
请注意,我们添加了
ng-model="search.term"
这基本上是将 Angular 模型绑定到此输入。如果您想知道为什么我们没有直接使用 ng-model="search"
,那么您将有机会在 此答案 中找到答案。
要将搜索词输出到您的浏览器控制台,只需像这样调整函数
$scope.performSearch = function (){
console.log("search term: " + $scope.search.term);
};
当您加载应用程序并点击 Search 按钮(不更改输入值)时,您应该会在控制台中看到
请注意,当应用程序加载时,cats
文本是如何自动填充的。这是一款强大的 双向 Angular 绑定。
Giphy API
最后,我们来到了激动人心的部分,也就是从服务获取数据并在我们的应用程序中显示它(在本例中,我们将显示图像)。
那么,我们如何获得这个 API 呢?嗯,如果您简单地 谷歌搜索 giphy api
并打开 第一个链接,您将获得其 API 文档。
那么,我们需要什么?嗯,我们需要搜索 API。如果您稍微滚动一下,您会找到以下链接
http://api.giphy.com/v1/gifs/search?q=funny+cat&api_key=dc6zaTOxFJmzC
很好,现在我们看到了我们需要创建什么样的请求来搜索 Giphy 的 GIF 数据库以查找特定术语。
如果您在浏览器中打开此链接,您将看到服务返回的内容。类似于
好的,现在怎么办?现在我们想从我们的应用程序中获取这个数据。好吧,但是我们怎么做呢?
Angular HTTP 请求
Angular 有一个 $http 服务,用于向某个服务 API 端点发送 HTTP 请求。
让我们稍微跳一下,将我们的 performSearch
函数更改为
$scope.performSearch = function (){
var searchTerm = $scope.search.term.replace(/ /g, '+');
console.log("search term: " + searchTerm);
var link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' + searchTerm;
$http.get(link).then(function(result){
console.log(result);
});
};
新代码逐行解释
- 添加了一个新的
searchTerm
变量,并对$scope.search.term
变量使用了replace
函数,其中带有全局匹配的正则表达式(g
开关),它基本上用+
替换所有空格。我们这样做是为了以防万一有人在我们的输入框中输入‘cats and dogs’。 - 将此新变量输出到控制台
- 添加了一个新的
link
变量并构建了它,以便将搜索词正确添加到链接中。 - 使用
$http
服务从link
变量定义的 URL 获取数据,并将结果打印到控制台
依赖注入
现在,如果您尝试运行该应用程序,您将在控制台日志中看到此内容
所以,我们看到 $http is not defined.
如果您以前熟悉 Angular,您会立即知道问题在于我们正在使用 $http
服务,但我们没有 依赖注入 它到我们的控制器中。我们只需在控制器定义中请求它即可实现此目的
.controller('SearchCtrl', function($scope, $http) {
如果您不熟悉依赖注入概念,可以 这里 阅读一些相关内容。
现在,如果您运行应用程序,在搜索词中输入一些内容并单击 Search 按钮,您将在控制台日志中看到类似以下内容
保存结果以备后用
在这里,您可以看到我们正在返回 result
对象,并且在其 data
属性中,有 25 个对象,它们保存了我们想在应用程序中显示的图像信息。
但是,我们如何在应用程序中显示这些图像呢?
我们看到 API 调用在 data
对象(再次在 data
对象内)中返回 25 张图像,让我们将其保存在某个变量中以备后用
$scope.giphies = [];
并且,让我们将 API 调用中的 25 个对象存储到此变量中
$scope.giphies = result.data.data;
供参考,将所有内容放在一个列表中,SearchCtrl
控制器现在的内容应该是
.controller('SearchCtrl', function($scope, $http) {
console.log("Hello from the Search controller");
$scope.search = {};
$scope.search.term = 'cats';
$scope.giphies = [];
$scope.performSearch = function (){
var searchTerm = $scope.search.term.replace(/ /g, '+');
console.log("search term: " + searchTerm);
var link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' + searchTerm;
$http.get(link).then(function(result){
$scope.giphies = result.data.data;
console.log($scope.giphies);
});
};
})
显示图像
现在这一切都很好,但我们不想将对象打印到控制台,我们想在应用程序中显示它们。
在检查了结果对象一段时间后,我们可以得出结论,要显示图像,我们需要定位到 images
对象,然后是 original
,最后是 url
属性。
要显示一张图像,我们可以在 tab-search.html 文件中添加一个 img
标签,然后定位到 giphies
数组的第一个元素,然后是 images
对象,然后是 original
,最后是 url
属性。同样,这种冗长的解释在代码中要好得多
<img ng-src="{{giphies[0].images.original.url}}">
当然,我们进行搜索,然后显示一张图像
但是,我们想要所有的 GIF,而不仅仅是一个!
为此,我们将使用 Angular 的 ng-repeat
<img ng-repeat="g in giphies" ng-src="{{g.images.original.url}}">
果然,现在有了所有 25 张图像。但是,我们希望它,你知道,好一点,因为您不是每天都能像这样从事一个企业级应用程序!
那么,我们该怎么办?我们进入 Ionic 文档,然后搜索一下……最后,我们选择了 Card 组件。
让我们将其代码复制到我们的 tab-search.html 中,但省略页脚部分,然后对其进行一些调整,将我们的 img
移入其中
<div class="card">
<div class="item item-divider">{{g.id}}</div>
<div class="item item-text-wrap"><img /></div>
</div>
到目前为止,您对此已经很熟悉了,但让我们指出我们已将 ng-repeat
从 img
标签移到具有 card
类的 div
标签上,这样我们就能为每个新的 GIF 重复这个漂亮的 Card
组件。哦,还有 {{g.id}}
就在那里,所以我们写了一些东西(在这种情况下是 GIF 的 id)。
样式
此时,我们非常高兴,但我们内在的设计师注意到我们的图像并不完全合适。我们精通设计和所有那些 CSS 小玩意,所以我们知道我们只需要给图像添加以下 CSS 规则
width: 100%;
SASS
但是,写普通的 CSS 太过时了(我们记得吗?2013 年;我们现在是 2016 年?),我想向您展示如何设置您的 Ionic 来与 SASS 一起工作。
我不会详细介绍,但 TL;DR 是 SASS 是 CSS 的升级版,它基本上允许您拥有函数、变量、混合等……在此处了解更多。
回到您之前运行 ionic serve --lab
的终端,并中断该进程 (CTRL + C
)。然后,执行以下命令
ionic setup sass
下一步是。哦,没有下一步了!一切都为您设置好了!为了不深入细节;Gulp 任务,正确的 index.html 包含等……
现在,您应该在 scss 文件夹中编写 SASS 代码。让我们创建一个新的文件 _custom.scss(下划线很重要!)在这里,内容如下
.card img {
width: 100%;
}
.centerText {
text-align: center;
}
并且,别忘了通过将以下内容附加到 scss 文件夹中的 ionic.app.scss 文件来导入它
@import "custom";
是的,您在这里导入时不需要下划线。
如果您想居中文本(我们显示 GIF ID 的地方),只需像这样添加类
<div class="item item-divider centerText">{{g.id}}</div>
现在只需再次运行 ionic serve --lab
并欣赏您的应用程序,其中包含精美的定位标题和设置精美的图像
学生成为大师
当然,您现在应该祝贺自己;您已经有了一个工作的应用程序!但老实说,把所有这些代码放在控制器里似乎有点脏,不是吗?此外,我们正在构建一个企业级应用程序,我们希望有一些结构并遵循正确的实践,对吧?
太好了,我很高兴您和我在一起。
我们将创建一个服务来获取这些 GIF。我们的服务(称为 Giphy
)看起来像这样(是的,将 performSearch
函数的先前全部内容替换为此)
scope.performSearch = function (){
Giphy.search($scope.search.term).then(function(result){
$scope.giphies = result;
});
};
另外,别忘了在控制器中注入 Giphy
.controller('SearchCtrl', function($scope, $http, Giphy) {
让我们编写一个服务
在 services.js 文件中,删除 Chats
工厂,而是添加
.factory('Giphy', function($http) {
return {
search: function(term) {
var searchTerm = term.replace(/ /g, '+');
var link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=' + searchTerm;
return $http.get(link).then(function(result) {
return result.data.data;
});
}
};
});
不要被奇怪的代码吓倒;它基本上是编写工厂/服务的样板代码。这里重要的是我们定义了一个名为 Giphy
的工厂,并且我们公开了一个名为 search
的函数,该函数接受 term
参数。
您可能会注意到我们基本上将控制器中的所有代码复制到了这个工厂。
唯一的区别是,在这里我们返回 $http.get
调用的结果,它基本上返回一个 Promise,我们可以在控制器中调用 then
。如果您不知道,Promise 的工作方式是,一旦 Promise resolve
(完成其任何任务),它就会激活 then
部分,然后我们就可以使用通过此 Promise 返回的数据来做一些事情。
另外,请注意我们注入了 $http
服务,以便我们可以像之前在控制器中一样使用它来进行 HTTP 调用。
那又怎样?!
发牢骚
您运行应用程序,它并没有更快,也没有更漂亮,它基本上与半小时前一样,那么有什么意义呢??
好了,通过这个,您将您的代码模块化了,这样您就可以通过注入所需的地方在任何其他控制器中使用 Giphy 服务。如果您没有这个,您将不得不通过控制器复制代码/粘贴代码。
这将导致代码重复,然后导致维护噩梦,这又会导致代码债务的累积,最终导致开发人员生活悲惨。
而且,您不希望这样,因为您是一个有抱负的开发人员,每天都在寻求进步。原谅这些老套的比喻,但说真的,这些天我看到太多人因为‘我不知道如何编写服务/工厂’这样的小原因而放弃。
但是,我为您感到高兴!因为能走到教程的这一步,您已经远远领先于其他人。继续学习和成长,您将在生活中做得很好!
/发牢骚
Ionic.io 和 Ionic View
您可以在模拟器/模拟器中测试应用程序;您可以通过在物理设备上运行来测试它。但是,您也可以通过 Ionic View 应用程序在您的手机上测试应用程序。
只需下载您手机上的应用程序,然后在 Ionic.io 上创建一个帐户。
一旦您有了帐户,通过执行以下命令在终端登录
ionic login
然后,最后,使用以下命令将应用程序上传到 Ionic.io
服务
ionic upload
完成后,您就可以在手机上的 Ionic View 应用程序中看到您的应用程序,并可以从那里运行它。
在 Github 上获取代码
这只是运行您需要的命令以将您的项目推送到 Github 的简要概述
- 在 Github 上创建一个项目
- 在项目根目录中执行
git init
git add .
git commit -m "my awesome app"
git remote add origin https://github.com/Hitman666/GiphySearch.git
– 确保这是 Github 上您的项目的正确 URLgit push -u origin master
更多学习材料请!
如果您有兴趣了解更多信息,可以通过 Leanpub 下载 4 篇文章的 PDF 版本,或者在这里阅读精简版(但仍然超过 10000 字的教程 这里。是的,您可以选择零作为金额,我保证我不会反对您 😉
结论
我们在这些见面会上的目标是‘见面’,学习新东西,互相帮助,如果实在不行,就和有相似兴趣的人在一起。
下一次见面会的主题将是‘JavaScript 和 Ionic 中的测试驱动开发入门’(倾向于提前准备的人可以阅读 这篇博文)。日期尚未确定,但将在八月底左右。
啊,最后,如果您想看看如何使用 Angular 2 构建完全相同的应用程序,您可以查看我为 Pluralsight 写的教程:通过构建 Giphy 搜索应用程序入门 Angular 2。
再见!