目录
在这篇文章中,您将看到如何为那些还没有Ionic框架环境的人设置它,然后您将逐步看到一个典型的应用程序。
上周,我在Čakovec举行了第一次Ionic框架聚会。在此,我要感谢TICM孵化和教育负责人Goran Levačić为我们确保了这次聚会的场地。
如果您对接下来的活动感兴趣,请务必查看聚会页面并在那里加入讨论。
这是关于什么的?
首先,我们展示了如何为那些还没有Ionic框架环境的人设置它,然后我们逐步完成了一个典型的应用程序。
演示应用
我们制作了一个简单的应用程序,使用Giphy网站的API搜索(和显示)GIF 。今天大多数应用程序都属于这一类。你有一个“某处”的服务,你在你的应用程序中调用它并显示它的数据。按照同样的原则,你可以为Youtube、IMDB等做一个应用程序。
那些已经非常熟悉 Ionic 的人可能会发现下面的速度太慢了。如果是这样,你可以看看源代码。
启动项目
首先,让我们使用以下命令(从终端执行)启动一个新的Ionic项目:
ionic start giphyApp
命令完成后,进入新目录:
cd giphyApp
仅出于测试目的,让我们运行应用程序以查看是否一切正常:
ionic serve --lab
您应该看到如下内容:
该--lab开关将为您提供并排查看应用程序在iOS和Android设备上的外观。
文件夹结构
现在,在你的编辑器中打开这个文件夹,你应该会看到类似这样的内容(我使用的是Sublime Text 3):
在开发Ionic应用程序时,您将大部分时间花在www文件夹中。
只是一个快速的TL;我们拥有的其他文件夹和文件的DR:
- Hooks——包含所谓的Cordova钩子,在Cordova构建项目时执行一些代码。根据我的经验,我还没有必要进行设置。
- 平台——包含构建项目时的平台特定文件
- 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模块。
好的,当然,这一切都很好,但我们仍然不知道要更改哪个文件!
好吧,如果我们看一下模板文件夹(当然,编辑器的搜索功能在这种情况下会派上用场;)我们会看到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标签。但我们不想要“聊天”选项卡!我们正在制作一个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控制台窗口中看到以下消息(这是在 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);
};
当您加载您的应用程序并单击“搜索”按钮(不更改输入值)时,您应该得到以下信息:
请注意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开关),基本上将所有空格替换为+。我们这样做是为了防止有人在我们的输入框中输入“过多的空格”。
- 将此新变量输出到控制台
- 添加了一个新link变量并对其进行构造,以便将搜索词正确添加到链接中。
- 使用该$http服务从link变量中定义的URL获取数据并将结果打印到控制台
依赖注入
现在,如果您尝试运行该应用程序,您将在控制台日志中看到:
所以,我们看到$http is not defined.
如果您以前熟悉Angular,您会立即知道这里的问题是我们正在使用该$http服务,但我们没有将它依赖注入到我们的控制器中。我们只需在控制器定义中要求它即可做到这一点:
.controller('SearchCtrl', function($scope, $http) {
如果你不熟悉依赖注入的概念,你可以在这里阅读一下。
现在,如果您运行该应用程序并在搜索词中输入内容并单击“搜索”按钮,您将在控制台日志中看到如下内容:
保存结果以备后用
在这里,您可以看到我们正在取回result对象,并且在它的data属性中,有25个对象,它们包含有关我们要在应用程序中显示的图像的信息。
但是,我们如何在我们的应用程序中显示这些图像?
我们看到API调用返回了data对象内的25张图像(同样在data对象内),让我们将其保存在某个变量中以供以后使用:
$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>
到目前为止,您已经是这方面的专家了,但请注意,我们用card类将ng-repeat从img标签移到了div标签,这样我们就可以在每个新的GIF中重复这个Card组件。哦,{{g.id}}在那里,以便让我们写一些东西(在本例中是GIFs id)。
样式
这一刻,我们非常高兴,但我们内心的设计师注意到我们的形象不太对劲。我们正在改变设计的东西和所有的CSS东西,所以我们知道我们只需要在图像中添加以下CSS规则:
width: 100%;
SASS
但是,编写普通的旧CSS是2013年(我们是2016年,记得吗?;),我想向您展示如何设置您的Ionic以与SASS一起使用。
我不会详细介绍,但TL;DR将是SASS是类固醇上的CSS,它基本上允许您拥有函数、变量、mixin 等……在这里了解更多信息。
返回您之前ionic serve --lab运行的终端并中断进程(CTRL+C)。执行以下命令:
ionic setup sass
而且,下一步是。哦,没有下一步了!一切都为你准备好了!不详述;Gulp任务,正确的index.html包括,等等……
现在,您应该在scss文件夹中编写您的SASS代码。让我们在这里使用以下代码创建一个新文件_custom.scss (下划线很重要!):
.card img {
width: 100%;
}
.centerText {
text-align: center;
}
并且,不要忘记通过将其附加到ionic.app.scss文件(包含在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的工厂,并且我们公开了接受term参数的search函数。
您可能会注意到,我们基本上将整个代码从控制器复制到了这个工厂。
唯一的区别是这里我们返回$http.get调用的结果,它基本上返回了Promise,我们可以在控制器中调用then。如果你不知道,promise的工作方式是,一旦promise resolves(完成它所拥有的任何任务),它就会激活then,然后我们对通过这个promise返回的数据执行某些操作的部分。
另外,请注意我们注入了$http服务,以便我们可以将它用于我们的HTTP调用,就像我们之前在控制器中所做的那样。
所以呢?!
你运行应用程序,它不是更快,它不是更好,它与半小时前基本相同,所以什么给了?
好了,有了这个,你模块化了你的代码,现在你可以在任何其他控制器中使用Giphy服务,只需在需要的地方注入它。如果你没有这个,你将不得不通过控制器复制/粘贴代码。
这将导致代码重复,进而导致维护噩梦,再次导致复杂的代码债务,最终导致开发人员的悲惨生活。
而且,您不希望自己这样做,因为您是一名有抱负的开发人员,希望每天都变得更好。原谅这些俗气的比喻,但实际上,这些天我看到太多人放弃的原因比“我不知道如何编写服务/工厂”更小。
但是,我为你感到高兴!因为在教程中做到这一点会让你遥遥领先。不断学习和成长,你会在生活中做得很好!
Ionic.io和Ionic视图
您可以在模拟器/模拟器中测试应用程序;您可以通过在物理设备上运行它来测试它。而且,您可以通过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上的项目的正确url
- git push -u origin master
结论
我们在这些聚会上的目标是“认识”彼此,学习新事物,互相帮助,如果没有别的,那就是和志趣相投的人一起出去玩。
本文最初发布于Build an Ionic app for searching gifs using Giphy API – Nikola Brežnjak blog
https://www.codeproject.com/Articles/5327557/Build-an-Ionic-App-for-Searching-gifs-using-Giphy