本文是翻译而来,留存以后观看,难免有错误之处,大家也可查看原文。 源码可以在Github上找到。
LokiJS是JS库,并使用内存数据库,所以拥有更快的性能,更加适合于hybrid app。其API和MongoDB很是相似。并且可以通过IndexedDB存储数据库,也可以通过使用JSON文件作为存储,甚至可以自己定义存储模式。
LokiJS被创造出来的原因之一是为了提供一个可以替代SQLite在cordova app中的作用。
LokiJS的缺点很明显,它不具有很强大的数据同步能力,但是其Changes API能够记录对本地数据库的所有更改,可以使用Changes API同步数据库。所以如果我们的app只需要在本地存储数据,使用LokiJS是再合适不过了,因为其对数据库的所有操作都在内存中完成,所以速度更快。
安装
在我们的ionic工程中,我们可以使用bower安装LokiJS:
$ bower install lokijs --save
安装完成后,下一步当然是在我们的index.html中引入LokiJS,因为LokiJS也支持angular,所以我们也将其对应于angular的JS文件引入:
<script src="lib/lokijs/src/lokijs.js"></script>
<script src="lib/lokijs/src/loki-angular.js"></script>
LokiJS默认存储数据到localStorage,但是localStorage并不可靠,因为当手机内存不足时,localStorage可能会被清除。
所以我们需要寻找其他解决途径,另一个选择是使用IndexedDB,但不幸的是IOS并不支持,那是因为Cordova使用的UIWebView不支持IndexedDB。
所以我们想到可以使用JSON文件作为存储,但眼下LokiJS在Cordova apps中没有保存文件的adapter,不过我们可以使用非官方的adapter:loki-cordova-fs-adapter达到我们的目的。loki-cordova-fs-adapter是Corentin Smith在ES6的基础上完成的,但是也可以下载向下兼容的版本。下载完成后,当然还是需要在index.html中引入:
<script src="js/loki-cordova-fs-adapter.js"></script>
这个adapter依赖于Cordova File Plugin,所以我们还需要安装此插件:
$ cordova plugin add cordova-plugin-file
注:也可以按照自己的想法创建adapter存储数据。
现在我们已经安装完成必须的库,下一步是将lokijs模块添加到我们app模块的依赖列表中:
angular.module('starter', ['ionic', 'lokijs'])
我们要创建的app
我们现在创建的app是一个生日保存app,可以添加、删除、更新、读取存储的生日信息:
构造Service
我们现在要构造一个service封装我们的LokiJS调用。
angular.module('starter').factory('BirthdayService', ['$q', 'Loki', BirthdayService]);
function BirthdayService($q, Loki) {
var _db;
var _birthdays;
function initDB() {
var adapter = new LokiCordovaFSAdapter({"prefix": "loki"});
_db = new Loki('birthdaysDB',
{
autosave: true,
autosaveInterval: 1000, // 1 second
adapter: adapter
});
};
return {
initDB: initDB,
getAllBirthdays: getAllBirthdays,
addBirthday: addBirthday,
updateBirthday: updateBirthday,
deleteBirthday: deleteBirthday
};
}
初始化LokiJS数据库有多种方法,本例中我们配置LokiJS数据库每秒自动保存数据到JSON文件中(autosave:true)。当然自动保存的功能足够智能,它知道仅仅当内存数据库改变时存储数据。
获取所有生日信息
很显然,上面定义了5个函数,我们只实现了一个,现在我们完成getAllBirthdays函数:
function getAllBirthdays() {
return $q(function (resolve, reject) {
var options = {};
_db.loadDatabase(options, function () {
_birthdays = _db.getCollection('birthdays');
if (!_birthdays) {
_birthdays = _db.addCollection('birthdays');
}
resolve(_birthdays.data);
});
});
};
在getAllBirthdays函数中,我们必须首先使用loadDatabase函数加载数据库。当加载完成后,我们可以在loadDatabase函数的回调函数中获得数据集。
如上所示,options对象是loadDatabase函数的第一个参数,如果你不想对从JSON文件中获取的数据做任何处理的话,你可以将其置空。然而,由于我们需要保存的生日信息不能被转自动换为Date对象,所以我们需要自定义infalte函数进行处理:
var options = {
birthdays: {
proto: Object,
inflate: function (src, dst) {
var prop;
for (prop in src) {
if (prop === 'Date') {
dst.Date = new Date(src.Date);
} else {
dst[prop] = src[prop];
}
}
}
}
};
我们只是将source对象的所有内容拷贝到destination对象,除了对Date属性作出处理,将其变更为Date对象。
增加、更新、删除生日信息
现在我们还需要完成“增加”、“更新”、“删除”生日信息的功能:
function addBirthday(birthday) {
_birthdays.insert(birthday);
};
function updateBirthday(birthday) {
_birthdays.update(birthday);
};
function deleteBirthday(birthday) {
_birthdays.remove(birthday);
};
创建UI
我们前面已经有了service给我们处理大部分工作,现在我们来创建UI。 首先我们先创建一个controller:OverviewController, 在OverviewController中调用birthdayService.initDB函数初始化数据库,为保证初始化顺利进行,我们需要等待$ionicPlatform.ready事件:
angular.module('starter').controller('OverviewController', ['$scope', '$ionicModal', '$ionicPlatform', 'BirthdayService', OverviewController]);
function OverviewController($scope, $ionicModal, $ionicPlatform, birthdayService) {
var vm = this;
$ionicPlatform.ready(function() {
// Initialize the database.
birthdayService.initDB();
// Get all birthday records from the database.
birthdayService.getAllBirthdays()
.then(function (birthdays) {
vm.birthdays = birthdays;
});
});
// Initialize the modal view.
$ionicModal.fromTemplateUrl('add-or-edit-birthday.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
vm.showAddBirthdayModal = function() {
$scope.birthday = {};
$scope.action = 'Add';
$scope.isAdd = true;
$scope.modal.show();
};
vm.showEditBirthdayModal = function(birthday) {
$scope.birthday = birthday;
$scope.action = 'Edit';
$scope.isAdd = false;
$scope.modal.show();
};
$scope.saveBirthday = function() {
if ($scope.isAdd) {
birthdayService.addBirthday($scope.birthday);
} else {
birthdayService.updateBirthday($scope.birthday);
}
$scope.modal.hide();
};
$scope.deleteBirthday = function() {
birthdayService.deleteBirthday($scope.birthday);
$scope.modal.hide();
};
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
return vm;
}
最后,我们处理index.html,进行界面设计,这里我们使用$ionicModal来展示“增加生日”和“编辑生日”的界面:
<body ng-app="starter">
<ion-pane ng-controller="OverviewController as vm">
<ion-header-bar class="bar-stable">
<h1 class="title">Birthdays</h1>
<div class="buttons">
<button ng-click="vm.showAddBirthdayModal()" class="button button-icon icon ion-plus"></button>
</div>
</ion-header-bar>
<ion-content>
<ion-list>
<ion-item ng-repeat="b in vm.birthdays" ng-click="vm.showEditBirthdayModal(b)">
<div style="float: left">{{ b.Name }}</div>
<div style="float: right">{{ b.Date | date:"dd MMMM yyyy" }}</div>
</ion-item>
</ion-list>
</ion-content>
</ion-pane>
<script id="add-or-edit-birthday.html" type="text/ng-template">
<ion-modal-view>
<ion-header-bar>
<h1 class="title">{{ action }} Birthday</h1>
<div class="buttons">
<button ng-hide="isAdd" ng-click="deleteBirthday()" class="button button-icon icon ion-trash-a"></button>
</div>
</ion-header-bar>
<ion-content>
<div class="list list-inset">
<label class="item item-input">
<input type="text" placeholder="Name" ng-model="birthday.Name">
</label>
<label class="item item-input">
<input type="date" placeholder="Birthday" ng-model="birthday.Date">
</label>
</div>
<div class="padding">
<button ng-click="saveBirthday()" class="button button-block button-positive activated">Save</button>
</div>
</ion-content>
</ion-modal-view>
</script>
</body>
结语
可以看出,使用LokiJS作为本地存储简单易用,唯一麻烦的地方是为ionic app选择合适的adapter。使用JSON文件的方式存储效果还是不错的,我已经在Android和IOS测试完成。
参考文档:
localStorage在混合移动应用中是不可靠的
ionic app中使用PouchDB+SQLite作为本地存储