1.服务简介
在有关Ionic的本系列的第一部分和第二部分中,我们设置了本地开发并建立了一些视图,以使用一些Ionic组件(例如基本导航和列表组件)加载公园列表。 在本教程中,我们将深入探讨Ionic如何提供许多服务,这些服务使您可以以编程方式管理应用程序和界面。
之前,我们演示了Ionic如何通过组件提供交互功能,这些组件用作HTML元素(实现为Angular指令)。 但是,有些接口元素对于用HTML实例化的组件没有意义,例如加载程序或操作表叠加层。
让我们先来看一下服务在您的应用程序中扮演的角色。 我已经确定了Ionic中的三种主要服务类型:
- 组件服务
- 代表服务
- 辅助服务
组件服务
组件服务使组件的使用成为可能,但不是使用HTML声明它们(就像我们在ionNavBar
看到的ionNavBar
),而是使用JavaScript对其进行管理。 换句话说,您将通过向控制器添加代码来利用这些组件。 在下面的示例中,我们将使用其中的两个。
将这些服务视为具有生命周期的组件可能会很有用。 通常,您希望它们在特定点加载,并在完成后将其删除。 例如, $ionicModal
允许您创建模式。 模态具有生命周期,出于特定原因可以打开和关闭模态。 您可能有一个要求用户登录的模式,或者他们可以关闭模型以跳过它,从而完成生命周期。
代表服务
某些组件具有随行委托服务,可以修改或管理该组件。 您可能要在组件创建后以编程方式对其进行操作,而这些服务旨在使这一点成为可能。 之所以这样命名,是因为它们将行为委托给了组件。
ionNavBar
组件具有一个名为$ionicNavBarDelegate
的委托服务。 这项服务有几种方法,但是title()
方法就是一个例子,它允许您更新导航栏的标题。 每个委托服务可用功能的范围各不相同,但应易于在文档中按名称标出它们。
辅助服务
最后一类是提供某种辅助功能或提供信息的服务。 只有少数几个,它们不太适合其他两个类别。 一些例子是:
-
$ionicPlatform
:帮助您与设备硬件进行交互 -
$ionicGesture
:允许您处理手势事件 -
$ionicPosition
:告诉您元素在屏幕上的位置
这些辅助服务倾向于帮助您开发逻辑或处理交互。 他们不会自行生成或修改组件。
在本教程中,我们还将介绍其他一些内容:
- CSS组件,仅是可视的,不提供功能逻辑,与其JavaScript组件的兄弟姐妹不同
- 离子事件,例如,当视图正在加载或完成加载时,我们可以利用它来挂钩事件
- 更多的导航功能,可以轻松导航,管理状态以及向导航栏添加按钮
源文件
在本教程中,我们将扩展在上一教程中开始的应用程序。 提醒您,该应用旨在向用户提供有关其本地公共设施(例如图书馆和公园)的信息。 该应用程序已经显示了芝加哥的公园列表,现在我们将添加显示负载指示器,查看单个公园详细信息屏幕,打开操作菜单以及实现一些基本共享功能的功能。
您可以在GitHub上查看完成的项目。 最后的示例也可以预览 。
您可以下载文件或使用Git签出。 将文件保存在计算机上后,需要运行npm install
来设置项目。 如果您使用Git签出代码,则可以通过运行git checkout –b start
来重新编码仓库以匹配最后一部分的结尾,从而进行编码。 拥有文件后,通过运行ionic serve
启动Ionic服务器。
2.实施加载指标
目前,该应用程序正在加载数据,并且无限滚动组件中会显示一个小圆圈指示器,直到加载为止。 但是,我们实际上要覆盖整个应用程序,因此很明显,该应用程序正在加载。
$ionicLoading
服务对于覆盖和阻止用户与应用程序交互直到加载数据非常有用。 它是可配置的。 例如,您可以声明是否显示加载图标或某些文本,是否需要背景,或在一定时间后是否自动隐藏。 您可以在下面的屏幕快照中看到正在使用的加载程序。
打开www / views / places.js进行一些修改以使用加载程序。 首先,我们需要通过在函数参数中添加$ionicLoading
将服务注入到控制器中。 该服务非常简单,它只有两个方法show()
和hide()
。 我们可以通过调用如本片段所示的方法来使加载器显示和隐藏。
.controller('PlacesController', function($http, $scope, $ionicLoading, Geolocation) {
var vm = this;
var base = 'https://civinfo-apis.herokuapp.com/civic/places?type=park&location=' + Geolocation.geometry.location.lat + ',' + Geolocation.geometry.location.lng;
var token = '';
vm.canLoad = true;
vm.places = [];
$ionicLoading.show();
vm.load = function load() {
var url = base;
if (token) {
url += '&token=' + token;
}
$http.get(url).then(function handleResponse(response) {
vm.places = vm.places.concat(response.data.results);
token = response.data.next_page_token;
if (!response.data.next_page_token) {
vm.canLoad = false;
}
$scope.$broadcast('scroll.infiniteScrollComplete');
$ionicLoading.hide();
});
};
});
加载控制器后,将立即调用$ionicLoading.show()
方法,这意味着它将立即触发。 现在我们需要告诉加载器在数据完成加载后隐藏,如您在$broadcast
之后看到的那样。
您可能会注意到,每次加载数据时都会调用$ionicLoading.hide()
方法。 这不是问题。 由于加载器已经被隐藏,因此此调用没有任何效果。
现在,我们已经实现了离子服务。 很简单 对? 有些比较复杂,我们将使用操作表来处理另一个示例。 不过,在开始之前,我们想扩展我们的应用程序,使其在注释列表和单独查看注释时都有两个视图。
3.添加便笺视图
我们的下一步是创建一个新视图,该视图将显示有关特定公园的更多详细信息。 各个公园的信息可能有所不同,但我们将重点关注获取图像,网站,电话和地址信息。 添加此视图的结果在此处显示。
要创建新视图,请在www / views / place / place.js中创建一个文件,并包含您在下面看到的内容。 这是place
视图的控制器和状态定义。
angular.module('App')
.config(function($stateProvider) {
$stateProvider.state('place', {
url: '/places/:place_id',
controller: 'PlaceController as vm',
templateUrl: 'views/place/place.html',
resolve: {
Place: function($http, $stateParams) {
var url = 'https://civinfo-apis.herokuapp.com/civic/place?place_id=' + $stateParams.place_id;
return $http.get(url);
}
}
});
})
.controller('PlaceController', function($scope, Place) {
var vm = this;
vm.place = Place.data.result;
});
如果您看一下config()
方法,您会发现我们正在声明一个新状态。 这是正在使用的ui-router,因此您应查阅ui-router文档以获取有关声明状态的所有详细信息。
对象定义显示我们正在使用/places/:place_id
的URL。 当您看到URL的前面带有冒号的一部分时,例如:place_id
,它会将路径的这一部分标记为状态参数。 该州可以使用$stateParams
对象提取该值并将其提供给您。 例如, /places/12345
将导致$stateParams.place_id = '12345'
。
您之前已经看过定义的其他部分,除了resolve
属性。 此功能使您可以在创建状态之前请求调用各种功能。 它接受键和函数值的对象,因此这里我们以Place
作为键,并将函数的结果分配给它。
在该函数中,它可以接受要注入的参数,类似于您可以对控制器执行的操作。 这里,注入了$http
和$stateParams
服务。 然后,该函数使用通过URL传递的place_id
的值,并生成并返回HTTP请求。 本质上,这是在位置视图中执行的操作,除了控制器执行的操作外。
解析功能足够聪明,可以确定如果您返回承诺,它将在创建状态之前等待该承诺解决。 换句话说, $http.get()
返回一个承诺以加载数据,并且ui-router等待,直到数据可用,然后再创建状态并将Place
传递给控制器。 解析功能对于在应用程序中预加载数据非常有用,这是如何利用它的相当基本的示例。
现在我们已经定义了状态,声明了控制器,并将Place
的结果数据(这是在状态中解决的)分配给vm.place
。 我们还需要为此状态制作模板,因此请在www / views / place / place.html创建一个新文件,并在其中添加以下内容。
<ion-view view-title="{{vm.place.name}}">
<ion-content>
<div class="card" ng-if="vm.place">
<div class="item item-text-wrap item-icon-left">
<i class="icon ion-map"></i> {{vm.place.formatted_address}}</p>
</div>
<div class="item item-image" ng-if="vm.place.photos[0].photo_reference">
<img ng-src="{{'https://civinfo-apis.herokuapp.com/civic/photo?photo_id=' + vm.place.photos[0].photo_reference}}">
</div>
<a ng-if="vm.place.website" class="item item-icon-left" ng-href="{{vm.place.website}}" target="_system">
<i class="icon ion-link"></i> {{vm.place.website}}
</a>
<a ng-if="vm.place.formatted_phone_number" class="item item-icon-left" ng-href="tel://{{vm.place.formatted_phone_number}}">
<i class="icon ion-ios-telephone"></i> {{vm.place.formatted_phone_number}}
</a>
</div>
</ion-content>
</ion-view>
该模板首先使用ionView
封装内容,因此Ionic导航系统可以正确跟踪它。 它还根据地点名称分配标题。 ionContent
包装器包含主要内容,您会注意到模板使用CSS类而不是元素来创建卡片组件。
在上一部分中 ,我们讨论了某些组件如何仅是CSS类。 卡就是一个例子。 从概念上讲,它就像一个列表。 内部内容像列表一样垂直堆叠,但样式看起来更像卡片。 这利用了卡片样式,包括图像支持,图标和文档中其他整洁的布局等功能。
由于不能保证返回的数据将具有电话号码或网站,因此使用了几个ngIf
指令。 ngIf
指令确保不显示任何空值。 它还使用ngHref
或ngSrc
正确构建链接。
您还会注意到tel://
协议的使用,当在tel://
使用tel://
协议时,应提示用户在选择该号码时拨打该号码。 这是一个方便的功能,易于使用,并且可以很好地集成到物理设备上。 根据您的设置,计算机上的某些程序(例如Skype)也可能会尝试为您拨打电话。
这应该给我们一个工作视图,但是我们如何导航到它呢? 我们需要做一些小的修改,以使导航从地方视图开始。
4.在视图之间导航
ui-router提供了ui-sref
指令,该指令用于将项目链接到另一个状态。 在这种情况下,我们希望场所视图列表中的每个项目都链接到相应的场所视图。
打开www / views / places / places.html并添加指令以链接到每个位置。 在ionItem
使用新属性更新ionItem
。
<ion-item ng-repeat="place in vm.places" class="item-avatar" ui-sref="place({place_id: place.place_id})">
ui-sref
指令具有一种格式,您可以通过其名称链接到另一个州,而不是像使用href
那样通过某些URL链接。 这很方便,因为URL可能会更改。 它还可以接受用于构建URL的参数,在本例中,我们希望传递place.place_id
属性。 ui-sref
将属性作为对象,因此state-name({param: value})
是语法。
现在预览应用程序并选择一个公园,它将导航到新的place
视图,您可以查看地址栏以查看URL添加了place_id
值。 但是,我们现在遇到了问题。 我们如何返回列表?
我们使用ionNavBackButton
功能为我们提供了自动后退按钮。 打开www / index.html并在ionNavBar
内添加以下代码段。 这将添加一个后退按钮,只有在有地方可以返回时,该按钮才会显示。
<ion-nav-bar class="bar-balanced">
<ion-nav-back-button class="button-clear">
<i class="ion-arrow-left-c"></i> Back
</ion-nav-back-button>
</ion-nav-bar>
Ionic的导航足够智能,可以在您使用应用程序时跟踪历史记录。 如果有上一个视图要返回,它将显示后退按钮。 否则,它将被隐藏。
我们还想声明位置视图永远不应该显示后退按钮,这可以通过在www / views / places / places.html中添加hideBackButton
指令来实现 。
<ion-view view-title="Local Parks" hide-back-button="true">
在浏览器中进行开发和预览时,有时会重置历史记录。 例如,在场所视图中并将更改保存到编辑器中时,浏览器会自动重新加载并重置历史记录。 在这种情况下,后退按钮不会按预期出现。 您可以通过返回列表并刷新以设置历史记录来解决此问题。
我们已经取得了不错的进展,但是现在,当您点击列表中的一个项目时,它将等待过渡到新视图,直到API调用返回数据为止。 它可能对您来说显示很快,但是如果API缓慢,则有时可能会变慢。 这可能会导致某人认为该应用程序卡住,运行缓慢,或者由于未立即开始对水龙头做出反应而未注册水龙头。 我们通过一些生命周期事件来解决这个问题,这些事件可以帮助我们设置要在这段时间内显示的加载程序。
5.在过渡期间添加加载程序
为了提供更好的用户体验,我们将使用$ionicLoading
服务在为位置视图加载数据时覆盖应用程序。 为了知道何时显示和隐藏加载程序,我们使用生命周期事件 。
这些事件是根据导航事件触发的,例如进入视图之前/之后或离开视图之前/之后。 您可以在这些时间点执行任何可能需要的操作,例如重置某些数据或使用它来提交使用情况信息。
为了说明这一点,让我们在位置视图中添加一个事件侦听器,以处理在您开始导航到位置视图时触发加载程序的事件。 打开www / views / places / places.js并将以下内容添加到控制器。 您还需要确保在控制器函数参数中声明了$scope
以便可用。
$scope.$on('$ionicView.beforeLeave', function() {
$ionicLoading.show();
});
这是一个作用域事件侦听器,正在侦听$ionicView.beforeLeave
事件(请参阅Angular作用域事件 )。 Ionic将此事件广播到您的控制器,并调用此处声明的匿名函数。 该函数只是调用$ionicLoading.show()
方法来打开加载程序。
一旦用户点击一个项目,这将触发加载程序出现。 现在,我们向地方视图添加了一个类似的代码片段,该代码片段用于在视图加载完成后隐藏加载器。 打开www / views / place / place.js并将以下内容添加到控制器中。 您需要将$ionicLoading
和$scope
都添加到控制器功能参数中,因为它们当前尚未注入。
$scope.$on('$ionicView.afterEnter', function() {
$ionicLoading.hide();
});
这侦听视图完成时触发的另一个作用域事件,并调用该函数隐藏加载程序。 在用户轻按要查看的位置的瞬间到视图完全加载之间的时间显示加载程序。 您可以尝试其他事件,看看它们何时触发。
在本教程中,我们要做的最后一件事是设置一个操作表共享按钮,该按钮可让您发布到Twitter,Facebook或电子邮件并共享公园信息。
6.使用操作表服务的共享按钮
操作表对于提供其他选项列表非常有用。 此意图通常用于您要提供已分组动作列表的情况,在我们的示例中,这是共享公园信息的方式列表。 我们将构建的操作表如下所示。
操作表服务比加载服务要复杂一些,因为它可以处理配置和用户输入。 打开www / views / place / place.js并将此新方法添加到您的控制器中。 您还需要确保将$ionicActionSheet
注入到控制器中。
vm.openSheet = function() {
var sheet = $ionicActionSheet.show({
titleText: 'Share this place',
buttons: [
{ text: 'Share via Twitter' },
{ text: 'Share via Facebook' },
{ text: 'Share via Email'}
],
cancelText: 'Cancel',
buttonClicked: function(index) {
if (index === 0) {
window.open('https://twitter.com/intent/tweet?text=' +
encodeURIComponent('I found this great place! ' + vm.place.url));
} else if (index === 1) {
window.open('https://www.facebook.com/sharer/sharer.php?u=' + vm.place.url);
} else if (index === 2) {
window.open('mailto:?subject=' + encodeURIComponent('I found this great place!') + '&body=' + vm.place.url);
}
sheet();
}
});
};
openSheet()
方法负责创建操作表。 它通过调用$ionicActionSheet.show()
执行此操作,该函数返回存储在sheet
上的函数。 这样,您以后可以通过调用sheet()
完成工作表的关闭。 show()
方法采用具有许多我们将要分解的属性的对象。 有几个遵循该模式的Ionic服务示例,例如模式和弹出窗口,因此您始终可以关闭它们。
该工作表使用titleText
属性管理标题,通常用于通知用户如何使用按钮。 cancelText
属性接受一个用于启用取消按钮的字符串。 如果您未声明,则不会选择取消按钮。 您也可以通过点击按钮外部的背景来取消。
要声明按钮,请使用buttons
属性,该属性是具有text
属性的对象数组。 它们按照声明的顺序显示,因此请对其进行排序。
buttonClicked
属性接受一个函数,并传递所选按钮的索引(如在buttons
中声明的那样)。 因此,您可以根据传递的索引确定要执行的操作。 在此功能中,将检查索引并打开Facebook,Twitter或使用mailto:
来触发电子邮件客户端。
它可能会在Facebook,Twitter或电子邮件应用程序中打开这些链接,具体取决于用户设置以及设备,但它至少会在应用程序外部(在外部浏览器中)打开链接。 最后一步是调用sheet()
方法,该方法将关闭操作表。
现在可以开始执行操作表了,但是我们仍然需要添加一个按钮来触发操作表。 为此,我们将导航栏按钮添加到调用vm.openSheet()
的位置视图中。 打开www / views / place / place.html并在ionView
和ionContent
之间添加ionNavButtons
片段。
<ion-view view-title="{{vm.place.name}}">
<ion-nav-buttons side="right">
<button class="button button-clear" ng-click="vm.openSheet()">
<i class="icon ion-ios-upload-outline"></i>
</button>
</ion-nav-buttons>
<ion-content>
这是另一个有用的Ionic导航功能,允许您使用ionNavButtons
将导航栏按钮添加到特定视图。 内部的任何按钮都将添加到导航栏中,您可以配置它们在哪一侧显示。
至此,一切正常。 用户可以打开操作表与他们的朋友共享公园。
结论
在本教程中,我们介绍了Ionic服务及其使用方式。 在此过程中,我们发现了许多其他离子功能:
在下一部分中,我们将进一步探究Ionic的一些导航功能。
如果您已经对Ionic框架感到满意,那么您可能要考虑参加Envato的Ionic模板的“最想要的竞赛” 。 怎么样? 创建一个唯一的Ionic模板,并在2016年4月27日之前将其提交给Envato Market。
最好的五个模板将获得$ 1000。 有兴趣吗 在竞赛网站上了解更多有关竞赛要求和指南的详细信息。
翻译自: https://code.tutsplus.com/tutorials/getting-started-with-ionic-services--cms-26278