Ionic 开发人员最常犯的 9 个错误
已发表: 2022-03-11介绍
Ionic 已经存在两年了。 它是一套很棒的工具,用于开发基于 AngularJS 的混合应用程序。 目前,Ionic 非常受欢迎,构建了超过一百万个应用程序,并且由数千名开发人员组成的社区不断壮大。
自从 Ionic 的第一个版本发布以来,时间已经过去了,Web 技术和最佳实践已经在许多方面发生了变化。 因此,在开始一个新项目时,很难确定要走哪条路。 在这些情况下,开发人员可能会犯错误,这可能会影响其应用程序的质量或团队的生产力。
通过阅读以下常见错误,您将掌握避免基本问题并使用 Ionic 创建高性能和可扩展应用程序的关键。
常见错误 #1:忘记启用原生滚动
Native Scrolling允许 Ionic 监听支持的 webviews 上的滚动事件。 它使Pull to Refresh 、 List Reordering和Infinite Scroll在没有 JavaScript 滚动的情况下成为可能,而 JavaScript 滚动是在浏览器缺乏适当的滚动事件时创建的。
自 Ionic 1.2(2015 年 12 月)起,Android 上默认启用原生滚动。 这是一个巨大的性能和用户体验改进,因为它确保了异步事件的平滑滚动。
不幸的是,由于 iOS 上缺乏适当的事件,该平台尚未启用本机滚动。
如果您使用的是 1.2 之前的版本,则可以使用$ionicConfigProvider
为 Android 启用本机滚动:
// Enable Native Scrolling on Android $ionicConfigProvider.platform.android.scrolling.jsScrolling(false);
您还可以使用任何ion-content
上的overflow-scroll
指令在任何页面上启用或禁用本机滚动:
<!-- Disable Native Scrolling on this page only --> <ion-content overflow-scroll=”false”>
请注意,很遗憾,collection-repeat 允许您的应用程序显示大量项目列表,但本机滚动无法覆盖。
常见错误 #2:不使用 Ionic CLI 安装平台和插件
Ionic CLI 为 Cordova CLI 添加了功能。 平台和插件持久性是 Ionic CLI 添加的一项很棒的功能。
Cordova CLI 的问题在于您安装的平台和插件仅安装在您的计算机上。 在团队工作时,为了避免错误,您希望共享相同的环境、平台和插件。 使用 Cordova CLI,使项目在开发人员机器之间保持同步变得更加困难。 是的,您可以提交平台和插件文件夹,但不建议这样做。
使用 Ionic CLI 安装平台ionic platform add ios
和 plugins ionic plugin add camera
时,适当编辑package.json
文件。
平台和插件存储在cordovaPlatforms
和cordovaPlugins
属性中:
"cordovaPlugins": [ "[email protected]", "[email protected]", "[email protected]" ], "cordovaPlatforms": [ "android", "ios" ]
现在,其他开发人员在拉取新代码时很容易保持同步,只需在必要时(添加、删除或版本更新)运行ionic state restore
。
常见错误#3:思维表现开箱即用
Ionic 基于 AngularJS,设备上的性能经常受到质疑。 在这一点上,我想向您保证:只要有一点 AngularJS 背景,您就可以使用 Ionic 创建世界级的应用程序。
完美的例子是使用 Ionic 构建的 Sworkit 应用程序,用户群超过 900 万,下载量超过 700 万,在 Google Play 上平均获得 4.5 颗星。
如果您想充分利用 AngularJS,那么在开始您的项目之前,您应该了解以下几点。
$手表
观察者习惯于监听 AngularJS 中的作用域变化。 $watch
基本上有四种类型: $watch (normal)
、 $watch (deep)
、 $watchCollection
和$watchGroup
。
它们中的每一个都是不同的,选择正确的可以在性能方面产生巨大的差异。
$手表(正常)
使用普通的$watch
只会检查现有的 Object 属性或 Array 项。 将不会处理诸如添加 Object 属性或将新项目推送到 Array 等浅层更改。
$scope.$watch('watchExpression', function(newVal, oldVal){ if(newVal){ // watchExpression has changed. } });
$watch(深度)
deep $watch
负责处理浅层变化和深层变化,例如嵌套对象属性。 有了这款$watch
,您一定不会错过任何修改。 但是,使用深度$watch
会影响性能。 我建议谨慎使用它。
$scope.$watch('watchExpression', function(newVal, oldVal){ if(newVal){ // watchExpression has changed. } }, true);
$watchCollection
$watchCollection
可以考虑介于普通$watch
和深度$watch
之间。 它也适用于比较对象引用,但优点是还可以通过添加 Object 属性或将新项目推入 Array 来浅层监视对象的属性。
$scope.$watchCollection('watchExpression', function(newVal, oldVal){ if(newVal){ // watchExpression has changed. } });
$watchGroup
在 AngularJS 1.3 中引入的$watchGroup
允许同时查看多个表达式。
虽然$watchGroup
与普通的$watch
相比可能不会提高您的应用程序性能,但它的优势是在查看多个范围表达式时更加综合。
$scope.$watchGroup([ 'watchExpression', 'watchExpression2', 'watchExpression3' ], function(newVals, oldVals) { if (newVals[0]) { // watchExpression has changed. } if (newVals[1]) { // watchExpression2 has changed. } if (newVals[2]) { // watchExpression3 has changed. } });
追踪
track by
用于避免在使用ng-repeat
时进行无用的 DOM 操作。 实际上,如果摘要循环发现您的集合中至少有一个元素发生了变化,那么ng-repeat
将重新渲染所有元素。 DOM 操作总是会对应用程序性能产生影响,所以越少越好。
为避免重新渲染整个集合并仅更新需要更新的元素,请使用带有唯一标识符的track by
。
<!-- if items have a unique id --> <div ng-repeat="item in items track by item.id"></div> <!-- if not, you can use the $index that ng-repeat adds to every of its items --> <div ng-repeat="user in users track by $index"></div>
只是避免在collection-repeat
上使用track by
。
一次性绑定
一次性绑定或::
是在 Angular 1.3 中引入的,它对您的应用程序性能产生了真正的影响。
基本上,在表达式上使用一次性绑定::
将在填充时将其从$watchers
列表中删除。 这意味着即使数据发生变化,表达式也无法更新。
<p>{{::user.firstName}}</p>
我们的建议是浏览您的应用程序的所有视图并考虑可以更新或不能更新的内容,并相应地使用一次性绑定::
。 对于消化周期来说,这将是一个巨大的解脱。
请注意,很遗憾,一次性绑定不能在collection-repeat
中使用,因为屏幕上显示的项目列表会随着滚动而改变。
如果您想了解更多有关 AngularJS 和 Ionic 性能提示和技巧的信息,我建议您阅读 Ultimate AngularJS 和 Ionic 性能备忘单。
常见错误 #4:与View Cache
逻辑混淆
默认情况下,单页应用程序不缓存页面。 您可能已经使用 AngularJS 应用程序体验过,当您在页面之间来回导航时,滚动或用户输入不会被保存。
使用 Ionic,默认缓存十页,这可以在全局或每个平台上进行更改。
// Globally $ionicConfigProvider.views.maxCache(5); // Per platforms $ionicConfigProvider.platform.android.views.maxCache(5); $ionicConfigProvider.platform.ios.views.maxCache(5);
这是一个很棒的功能,但有时初学者很难理解如何处理缓存页面。
问题是当用户返回到一个缓存页面时,控制器不会再次被重新实例化,这与 AngularJS 应用程序不同,一切就像你从未离开过那个页面一样。
在这些情况下,您应该如何更新页面上的数据?
介绍控制器生命周期事件
与 AngularJS 相比,Ionic 提供了许多生命周期事件:
$scope.$on('$ionicView.loaded', function(){}); $scope.$on('$ionicView.unloaded', function(){}); $scope.$on('$ionicView.enter', function(){}); $scope.$on('$ionicView.leave', function(){}); $scope.$on('$ionicView.beforeEnter', function(){}); $scope.$on('$ionicView.beforeLeave', function(){}); $scope.$on('$ionicView.afterEnter', function(){}); $scope.$on('$ionicView.afterLeave', function(){});
如果您想控制视图缓存,这些事件是必需的。
例如,第一次加载视图时触发$ionicView.loaded
事件。 当这个视图被缓存时,这个事件将不再被触发,即使用户回到它。 这通常是您用来启动变量的事件,就像在 AngularJS 中使用$viewContentLoaded
事件一样。

如果您想在每次进入视图时获取数据,无论是否缓存,您可以使用$ionicView.enter
事件。
通过在正确的时间使用正确的事件,您可以提高应用程序的可用性。
关于性能,使用缓存视图只会影响 DOM 的大小。 当一个页面被缓存时,它的所有观察者都断开连接,因此该页面只是位于页面上等待再次使用的更多 DOM 元素。
DOM 的大小对于获得良好的用户体验很重要,但是缓存多达 10 个页面似乎可以正常工作(当然,这取决于您在页面中加载的内容)。
常见错误 #5:不了解 Android 的 Crosswalk
每个 Android 版本都运行不同的 WebView(运行您的应用程序的浏览器)。 不同设备的性能不同,在旧的 Android 设备上可能非常糟糕。 要在每台 Android 设备上获得相同的流畅性和响应性体验,您可以安装 Crosswalk。 它基本上将最新的 Chromium 浏览器嵌入到您的应用程序中,并且每个 APK 增加了大约 20Mb,包括 ARM 和 X86。
可以使用 Ionic CLI 或 Cordova CLI 简单地安装 Crosswalk:
ionic plugin add cordova-plugin-crosswalk-webview
常见错误 #6:试图在浏览器中运行 Cordova 插件
大多数使用 Ionic 的开发人员都希望他们的应用程序可以在 iOS 和 Android 上运行。 添加平台ionic platform add ios android
和一些插件ionic plugin add cordova-plugin-device-orientation cordova-plugin-contacts
后,一个菜鸟的错误是认为你可以在浏览器中测试它们。 好吧,您可以,但前提是您安装了正确的浏览器平台。 请记住,它不适用于所有插件。
Cordova 的插件旨在通过 JavaScript 与本机设备 API 进行交互。 因此,联系人插件或设备方向插件只能在设备上运行。
但是,您可以轻松地在设备上测试您的代码,并通过您的计算机对其进行远程调试。
Android 上的远程调试
插入您的设备并通过运行adb devices
确保您的计算机正确检测到它(需要 Android SDK)。
通过运行ionic run android
构建您的应用程序并将其安装在您的设备上。 在设备上启动您的应用后,通过 Chrome 开发工具(在您的计算机上) chrome://inspect/#devices
打开控制台,然后检查您的设备。
iOS 上的远程调试
插入您的设备并确保它被您的计算机正确检测到。 通过运行ionic run ios --device
构建您的应用并将其安装在您的设备上。
在设备上启动您的应用程序后,通过单击“ Develop > Your iPhone > Your app
”打开 Safari 开发工具(在您的计算机上):
在浏览器中运行 Cordova 插件
在浏览器中运行 Cordova 插件是您应该了解的高级功能。 从 Ionic 1.2 开始,浏览器得到官方支持,开启了超越 iOS 和 Android 平台的跨平台应用时代。
借助 Cordova 浏览器平台、Electron 和唯一的 Web 技术(JavaScript、HTML 和 CSS),我们现在可以为浏览器和桌面(Windows、Linux 和 OSX)构建 Ionic 应用程序。
Github 上提供了一个入门工具包。
Cordova 浏览器平台
使用浏览器平台,您可以为浏览器创建 Cordova 应用程序。 这意味着您也可以在浏览器上使用 Cordova 的插件。
它可以像安装 iOS 或 Android 平台一样安装:
cordova platform add browser
您的应用程序需要在使用前编译,与 iOS 或 Android 完全相同:
cordova run browser
此命令将编译您的应用程序并打开您的默认浏览器。
跨平台插件
网络、相机和 Facebook 等许多插件同时支持 iOS、Android 和浏览器平台 - 都使用相同的 API。
为了说明有一种方法可以使用 ngCordova API 了解您的设备在每个平台(iOS、Android、浏览器和桌面)上是在线还是离线:
// listen for Online event $rootScope.$on('$cordovaNetwork:online', (event, connectionType) => { this.isOnline = true; }); // listen for Offline event $rootScope.$on('$cordovaNetwork:offline', (event, connectionType) => { this.isOnline = false; });
考虑到这一点,您现在可以想象使用一个代码库创建可以在任何地方运行的产品。
常见错误 #7:遵循大型应用程序的入门套件架构
使用ionic start myapp
命令时,会创建一个具有以下文件夹结构的启动项目:
www/ js/ app.js controllers/ aaa.js bbb.js ccc.js services/ xxx.js yyy.js zzz.js templates/ aaa.html bbb.html ccc.html
这称为按类型分类的结构,其中 JavaScript、CSS 和 HTML 文件按类型分组。 对于初学者来说似乎很容易,这种架构很快就会失控。 它根本无法扩展。
以下是不使用 Folder-by-Type 结构的一些原因:
- 文件夹中的文件数量可能会很大
- 查找您需要为特定功能修改的所有文件可能会很棘手
- 处理一项功能将导致许多打开的文件夹
- 不能很好地扩展,应用程序增长得越多,工作就越困难
我更推荐使用 Folders-by-Feature 结构,其中 JavaScript、CSS 和 HTML 文件按功能或 AngularJS 模块分组:
myNewFeature/ index.js (AngularJS module) config.js service.js controller.js index.html style.scss
使用 Folders-by-Feature 结构的原因:
- 文件夹中的文件数量限制为少数
- 查找您需要为特定功能修改的所有文件很容易 - 它们位于同一个文件夹中
- 您可以独立处理功能
- 知道模块代表什么很容易 - 文件夹名称就足够了
- 轻松创建新功能,只需复制/粘贴现有功能
- 扩展性好,您可以根据需要添加任意数量的新功能,而不会让您的团队难以工作
请注意,这种架构接近于现在 Angular2/Ionic2 应用程序中默认的 Folders-by-Component 结构。
常见错误 #8:将事件绑定到onscroll
,而忘记了requestAnimationFrame
这个单一的陷阱通常是初学者的错误,但它可能对性能产生最严重的影响。 考虑一下:
<ion-content on-scroll="getScrollPosition()"> // … </ion-content>
$scope.getScrollPosition = function () { // heavy processing, like manipulating DOM // or anything that triggers a $digest() // will be called every ~80ms, // and will impact UX }
尽管 Ionic 为这些操作提供了节流,但它仍然可能非常慢。 基本上,任何触发摘要循环的东西都应该被推迟,而不是与重绘一起触发,这也是滚动的效果。
开发人员一直试图通过绑定到滚动事件(尤其是动画)来实现的许多目标也可以使用不同的方法来实现。 看requestAnimationFrame
。
var myElement = document.getElementById('content'); var elemOffsetFromParent = myElement.offsetTop; function onCapturedFrame() { if (window.scrollY >= elemOffsetFromParent) { customTweenFunction(myElement, options); } window.requestAnimationFrame(onCapturedFrame); } onCapturedFrame();
上面的代码是一个非常简单的例子,检查用户是否滚动到元素的顶部。 如果您打算使用该示例,请记住添加特定于供应商的替代方案以实现跨浏览器兼容性。 它基本上会以最佳速度运行,具体取决于浏览器、60 FPS 或屏幕刷新率。 但它是经过优化的,高性能动画框架使用了这种简单的方法。
您可能还想查看element.getBoundingClientRect()
,它提供有关 HTML 节点大小和位置的信息。
常见错误 #9:手动设计离子应用程序原型
Ionic 有一个特定的设计,几乎是一种视觉语言。 特别是对于原型和早期产品,利用可用的组件和样式可以节省大量时间和费用。 它们实际上相当小,并且具有良好的美感。
呈现具有基本功能的线框和模型已成为行业标准。 在移动设备上查看图片和查看带有动态组件的实际应用程序是两种截然不同的茶。 许多设计师和 UX 开发人员使用 Axure 或 Balsamiq 等工具,它们可以快速制作功能最少的线框。
现在,Ionic 的创建者发布了一个专门为 Ionic 开发人员制作的类似工具。 它被称为离子创造者。 它有一个拖放 Web 界面,并支持几乎所有核心 Ionic 提供的东西。 它的优点在于它允许将原型导出为多种格式,使用标准的工作 Ionic 代码,甚至构建应用程序并共享它。 该工具是专有的,但许多选项可以免费使用。
结论
Ionic 以一种没人能想象的方式彻底改变了混合应用行业。 然而,随着时间的推移,最佳实践和工具缺乏演变。 结果,开发人员可能犯的潜在错误的数量增加了。
专业的 Ionic 开发人员有一种清晰的方法可以同时向多个平台交付世界级的应用程序。 方法是利用可用的工具,将性能作为重中之重,并遵循最佳实践。
如果没有了不起的 Ionic 社区 Michal Mikolajczyk、Mike Hartington(Ionic Core 团队)和 Katie Ginder-Vogel(Ionic 营销与传播经理)的创造力,这篇文章是不可能完成的。 非常感谢大家。