前两篇的入门教程相信大家已经对APICLOUD如何开发一个APP有了了解,当然这只是个教程,更多的是大家动手练习。
今天给大家带来的是进阶性的教程了,利用文件缓存存储充分发挥你的APP性能,提高用户体验度。一个好的APP不是单纯的几个JS就搞定的,我们得多动手多写点东东来优化,提高用户的体验,这个过程是比较繁琐的,大家可以跟自己的团队一块协商更好的优化解决方案。
我们在使用一些APP的时候会发现从列表页打开内容页基本是秒开;使用QQ或微信上传多图时也没有图片的等待效果。下面我们就围绕着这两个案例来讲解。
一:列表页和内容页的文件缓存存储方案
先看一个流程图:
借着上面的流程图我们对开发思路先有个了解,我们存储的时候可以选择一些比较死的数据来存储,比如用户发布一条动态后,用户的信息和动态内容数据是死的,回复点赞等信息是更新繁琐的,我们就可以将用户的基本信息和动态基本内容保存到本地。
实现此功能用到的主要方法为 writeFile和readFile,在存储数据时注意转换JSON数据为字符串,读取的时候在将其转换为对象,下面开始说一下基本代码,主要讲一下内容页这块的存储,列表也存储相对要简单点,留给大家作为作业来练习
列表页实现代码:
声明两个全局标量page和lastId。同时还声明了要一个lock变量,防止滚动加载时重复
var page=1,lastId=0,lock=false;
使用ajax从服务器获取数据
我写了个ajax的通用方法,我们下面讲的就数据读取就全部用这个来,
function ajaxRequest(url, method, datas, callBack) {
var serverUrl = 'http://www.xxx.com/';
var now = Date.now();
api.ajax({
url: serverUrl + url,
method: method,
cache: false,
timeout: 30,
dataType: 'json',
data: {
values: datas
}
}, function (ret, err) {
callBack(ret, err);
});
}
下面在代码中注释说明实现
function getData(){
var getDataUrl = '你的URL&page='+page;
ajaxRequest(getDataUrl, 'GET', '', function (ret, err) {
if (ret) {
//获得最后一条数据id,主要是判断下拉刷新的时候用
if(ret[0].id>lastId){
lastId = ret[0].id;
}
var html = '';
for(var i in ret){
/*下面就是往容器里面插入数据的代码*/
html += '<div id="'+ret.id+'">';
/*.......*/
html += '</div>';
}
/*下面这块代码根据自己的实际情况来写*/
if(page>1){
//el为你的容器
//当页数大于第一页的时候,在最后一个子元素后面插入HTML
$api.append(el,html);
lock = false;
}else{
//其他直接写入,这个
$api.html(el,html);
lock = false;
}
//将数据内容写入本地文件的一个函数,这里的ret是个多维数组
writeFile(ret);
} else {
// do
}
})
}
//将列表数据写入缓存文件
function writeFile(json){
//缓存目录
var cacheDir = api.cacheDir;
for(var i=0;i<json.length;i++) {
//内容的ID
var id = json.id;
//内容的数据,内容的数据存储时就根据自己的需要来看存储哪些,可以循环过滤一下
var dataJson = json;
//写入文件
api.writeFile({
//保存路径
path: cacheDir+'/'+id+'.json',
//保存数据,记得转换格式
data: JSON.stringify(dataJson)
}, function(ret, err){
})
}
}
这样内容就分别存储到本地里面,其他下拉刷新,滚动加载会在整理到后面的JS文件里面
注意上面保存的文件名是用id来保存的,也可以根据自己的需要来加前缀或者目录。
在打开内容页的时候我们一般是在onclick加上内容ID,来判断。我们就根据这个id首先来判断有没有本地存储文件,没有的话再从服务器获取。
内容页JS实现代码
function getData(){
var cacheDir = api.cacheDir;
api.readFile({
path: cacheDir+'/'+id+'.json'
}, function(ret, err){
if(ret.status){
//如果成功,说明有本地存储,读取时转换下数据格式
var jsonData = JSON.parse(ret.data);
//自己写操作json的代码啦
}else{
//如果失败则从服务器读取,利用上面的那个ajaxRequest方法从服务器GET数据
}
});
}
注,上面的getData放在对应页面的apiready里面
是不是看着相当的简单,主要是一种思路,多写点代码就能让用户体验度提高一点
下面再来点复杂点的
二,用户大数据静默上传方案
在APP中我们会做到这样一个功能,用户多图上传。而现在随着手机像素越来越高,图片越来越大,本身手机网络速度有限,上
传多张照片的时候是非常困难的,尤其是等待时间。总不能让用户发个东西在那傻傻的等待吧,下面提供一个简单解决思路,同样主要还是利用writeFile
和readFile来实现,同时利用了大量的监听事件。
先看图
里面有几个知识点,sendEvent 、 addEventListener、 图片压缩上传
我们理下思路:
用户发布完数据后先写入本地文件并同时给列表页发送要给监听事件。当列表页收到监听这个事件后开始读文件并将本地的数据先
插入列表页(这里插入的时候可以给列表页加个同步至服务器的loading动画),然后开始与服务器同步数据(基本信息写入,图片压缩后上传)。上传成功
后再来删除文件刷新列表页等操作。
数据写入到本地和读取这个就不用多说了吧,按照上面说的writeFile和readFile来实现
当写入成功后加一个sendEvent事件
var cacheDir = api.cacheDir;
api.writeFile({
path: cacheDir+'/waiting'+date+'.json',
data: JSON.stringify(data)
}, function(ret, err){
if(ret.status){
//发送个事件
api.sendEvent({
name: 'waitUpload',
extra:{fileName:'waiting'+date}
});
api.toast({
msg: '发布成功',
duration:1500,
location: 'top'
});
setTimeout(function(){
api.closeWin({
name: ''
})
},1000);
}else{
api.toast({
msg: '发布失败',
duration:2000,
location: 'top'
});
}
})
回到列表页在apiready里面来监听这个事件
apiready = function(){
//监听最新发布(本地缓存)
api.addEventListener({
name:'waitUpload'
},function(ret){
if(ret && ret.value){
var value = ret.value;
var cacheDir = api.cacheDir;
api.readFile({
path: cacheDir+'/'+value.fileName+'.json'
}, function(ret, err){
if(ret.status){
//如果监听到事件,先利用readFile来读取数据并写入到列表页,就省略这块了
//加了个延迟来同步服务器,传入数据,我这里的数据后面加了个0,因为在开发的时候我用了doT模板引擎,在发布保存的时候我组装的是一个多维数组,然后这里只取了第一个数组。
setTimeout(function(){
synchroServer(newDataArr[0]);
},500)
}
});
}
})
}
同步到服务器,在服务器数据库里面我是这样来实现的
分表一个是基本数据表和一个图片表)
基本数据传完后返回一个内容ID,然后开始处理图片数据,先压缩图片,然后转为base64来上传,上传时同时传递了内容ID。
上传图片是循环上传的,记录一个上传图片成功的次数,如果这个次数等于图片数量就表示成功了,然后执行全部数据上传完成的操作。我这里没有做断点续传等类的操作,自己可以扩展下,。这里还是用里fs模块来执行删除文件,直接贴代码,在代码里面说明
function synchroServer(data){
var fs = api.require('fs');
isSynchro = true;
postDataUrl = '';//基本数据发送的URL
var updatePhotosUrl = '';//图片上传类的URL
ajaxRequest(postDataUrl, 'post', data, function (ret, err) {
if (ret) {
if(data.photos.length>0){
/*如果有图片*/
//这里是我在自己的项目中写一个状态的判断,保留了一下
var loadingName = $api.byId('loading-name-waiting'+ret.synchrotime);
$api.text(loadingName,'上传图片');
//循环执行图片的压缩和上传操作
for(var i in data.photos){
var img = new Image();
img.src = data.photos;//图片路径
img.onload = function () {
var that = this;
//生成比例
var w = that.width,
h = that.height,
scale = w / h;
w = 640 || w;
h = w / scale;
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
$api.attr(canvas,'width',''+w+'');
$api.attr(canvas,'height',''+h+'');
ctx.drawImage(that, 0, 0, w, h);
var base64 = canvas.toDataURL('image/jpeg', 1 || 0.6 );
var upData = {
userid: userid,
dynamicid: ret.id,
base64: base64
}
//上传
ajaxRequest(updatePhotosUrl, 'post', upData, function (retI, errI) {
if(retI){
//全局变量记录成功次数
uploadNum += 1;
if(uploadNum==data.photos.length){
//全部完成后
$api.text(loadingName,'上传完成');
uploadNum=0;
isSynchro = false;
//删除正在上传的dom,并刷新
setTimeout(function(){
var dynamicIng = $api.byId('dynamic_waiting'+ret.synchrotime);
$api.remove(dynamicIng);
//这是一个等于下拉刷新的方法,自己可以根据前面说的lastId来判断实现
getNewData();
//删除本地缓存文件
fs.remove({
path: api.cacheDir+'/dynamic/waiting'+ret.synchrotime+'.json',
},function(ret,err){
});
},1000)
}
}
})
}
}
}else{
//如果没有图片的操作,根据上面自己去写
}
} else {
}
})
}
===========================================================================
大家先根据上面的思路自己练手完成,有问题可以在楼下回复。然后根据反馈情况后面补上全部demo。现在放出demo只会让大家变懒,谢谢理解。
新手入门教程,从0开始入手APIcloud(一)
新手入门教程,从0开始入手APIcloud(二)
新手进阶教程,从0入手APICloud(三)-- 缓存方案