项目也总算正式上线了,终于有时间来记录这段时间在项目中的一些问题和不足了。
1.onLoad和onShow
onLoad: 页面加载的时候触发,只触发一次,从二级页面回来时不会触发。
onShow:页面显示的时候触发,只要进入或返回该页面就会触发,从二级页面回来也会触发。
例子:
第一次进入A页面,会依次触发onLoad和onShow方法,再进入B页面,从B页面返回到A页面时会触发onShow方法。
onSHow方法用来刷新页面比较合适,onLoad方法适合用在初始化加载数据时。
onLoad在onShow之前触发。
2.安卓应用加载网络图片,解决缓存不能正常更新图片的问题
图片是从服务器获取直接放在页面加载的,所以当页面加载之后图片也加载完成,但由于安卓应用会自动缓存加载过得图片,当服务器修改过同名的图片时,APP中并不会显示新的图片。这个问题一直困扰良久,后来想到一个方法就是直接给网络图片加一个时间戳,一秒更新一次,这样的话就不会出现缓存不显示正确图片的情况了,但这样做会导致另外的问题就是当网络不好或断网的情况下,图片不能显示…大家如果有更好的方法的话欢迎分享哟~
let now = new Date();
// 创建时间戳 (由于计算出的是毫秒为单位的时间戳,请求时间过快,并不符合实际需求,所以转换为秒的时间戳就行)
let time = now.getTime()/1000;
let img = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575437545598&di=04d0f1f2dc5165ff441b66b0f6a38423&imgtype=0&src=http%3A%2F%2Fwx3.sinaimg.cn%2Forj360%2F005ZWRGigy1g7moazx0hnj30dw08qwfb.jpg?t=' + time
3.setInterval()和setTimeout()的区别
setInterval()和setTimeout()常被用来处理延时和定时任务。
setTimeout:用于在指定的毫秒数后调用函数或计算表达式。
setInterval:在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval清除该定时器。
表达式:
setTimeout(()=>{
// 逻辑代码
},1000)
setInterval(()=>{
// 逻辑代码
},1000)
注:若只是想做延迟执行某方法或功能的话,建议使用setTimeout,尽量少使用setInterval。
可使用setInterval刷新表单,对于一些表单的假实时指定时间刷新同步。
如:
let timer = setInterval(() => {
// 根据flag来判断是否暂定定时器
if(this.flag) {
// 从后台获取数据,更新数据
uni.resquest({
url: "",
method: "",
header: {},
success: (res) => {
this.data = res.data
},
fail: (err) => {
console.log("请求失败:"+err)
}
})
} else {
// 使用clearInterval来结束该定时器
clearInterval(timer)
}
}, 8000)
(每8秒执行一次任务,当this.flag为false是清除该定时器的任务)
以上是举的简单例子用来刷新后台给的数据,并没有判断状态码,也没有做性能优化方面的处理,请勿在项目中直接这样使用。
setInterval的弊端
(1)无视代码错误
对调用的代码是否报错并不会有其他提示,即使调用的代码由于某种原因出错,它还是会在没有碰到clearInterval的情况下
持续不断的调用该代码。
(2)无视网络延迟
由于某些原因(服务器过载、临时断网、流量剧增、用户带宽受限,等等),请求的实际时间会增加,但setInterval仍然
会按定时持续不断地触发请求,最终导致客户端网络队列会被塞满。
4.Math对象常用方法
// 1.只保留整数部分(丢弃小数部分)
parseInt(5.1234);// 5
// 2.向下取整(<= 该数值的最大整数)和parseInt()一样
Math.floor(5.1234);// 5
// 3.向上取整(有小数,整数就+1)
Math.ceil(5.1234);
// 4.四舍五入(小数部分)
Math.round(5.1234);// 5
Math.round(5.6789);// 6
// 5.绝对值
Math.abs(-1);// 1
// 6.返回两者中的较大值
Math.max(1,2);// 2
// 7.返回两者中的较小值
Math.min(1,2);// 1
// 8.随机数(0-1)
Math.random();
// 解析字符串 返回浮点数 若不是数字 则返回NaN
parseFloat('5.1234'); // 5.1234
5.Date对象
Date对象具体的属性和方法请查看官方文档:点击此处查看官方文档
例子:获取当前时间的下周二14:00,若不足一天则使用倒计时,否则倒计天数。
// 使用面向对象 比直接使用时间戳要简单的多
getEndTime(globalCurrentDate) {
// globalCurrentDate 是当前时间
var now = new Date(globalCurrentDate);
var nowTime = now.getTime(); // 获取当前时间戳
this.currentTime = nowTime;
var endDate = new Date(); // 创建当前时间对象
var day = now.getDay(); // 获取今天是周几
var oneDayTime = 24 * 60 * 60 * 1000; // 一天的时间
// 周天
if (day == 0) {
day = 7;
}
// 周一 获取结束对象
if (day == 1) {
// 周一的结束对象为当前时间(周一)+一天的时间
endDate.setTime(nowTime + oneDayTime);
} else if (day == 2) { // 周二 获取结束对象
// 周二的结束对象就是当前时间
endDate.setTime(nowTime);
// 判断结束时间戳是否小于当前时间 若当前时大于结束时间 则为下个周二
if (endDate.getTime() < nowTime) {
endDate.setTime(nowTime + (9 - day) * oneDayTime);
}
} else if (day >= 3) { // 周三到周天则为正常的倒计天数 获取下周二的对象
// 当前时间+ (9 - day) * 一天时间
endDate.setTime(nowTime + (9 - day) * oneDayTime);
}
endDate.setHours(14, 0, 0, 0); // 下周二的结束时间
let endTime = this.dateFormat(endDate, 'yyyy年MM月dd日'); // 将结束对象转为日期
this.lastTime = endTime.split('年')[1]; // 周二的日期
let days = (endDate.getTime() - nowTime) / oneDayTime; // 剩余天数
if (days >= 1) {
this.retaminDays = Math.ceil(days); // 向上取整获取剩余天数
} else {
this.continueTime((endDate.getTime() - nowTime) / 1000); // 24小时倒计时
}
},
// 倒计时
continueTime(params) {
// 根据params倒计时
let timer = setInterval(() => {
if (params > 0) {
this.currentTime++; //根据当前时间++
params--;
this.retaminDays = this.secToTime(params);
} else {
// 时间结束
this.retaminDays = '00:00:00';
}
}, 1000);
},
// 将秒转为 时:分:秒
secToTime(time) {
let t = '';
if (time >= 0) {
let hour = Math.floor(time / 60 / 60) % 60;
let min = Math.floor(time / 60) % 60;
let sec = time % 60;
if (hour < 10) {
t = '0';
}
t += hour + ':';
if (min < 10) {
t += '0';
}
t += min + ':';
if (sec < 10) {
t += '0';
}
t += sec;
}
return t;
},
// 获取截止日期
dateFormat(time, format) {
var t = new Date(time);
var tf = function(i) {
return (i < 10 ? '0' : '') + i;
};
return format.replace(/yyyy|MM|dd|HH|mm|ss/g, function(a) {
switch (a) {
case 'yyyy':
return tf(t.getFullYear());
break;
case 'MM':
return tf(t.getMonth() + 1);
break;
case 'mm':
return tf(t.getMinutes());
break;
case 'dd':
return tf(t.getDate());
break;
case 'HH':
return tf(t.getHours());
break;
case 'ss':
return tf(t.getSeconds());
break;
}
});
}
以上方法还可以简单一些,但是由于本人对时间实在掌握的不是很好,所以只能做到这里了。各位有意见可以提哦~~
6.eval()和JSON.parse() JSON.stringify()
(1)eval()
W3C中对eval()函数的解释是:可计算某个字符串,并执行其中的JavaScript代码。
示例:
eval("x=10;y=20;document.write(x*y)") // 200
document.write(eval("2+2")) // 4
var x=10
document.write(eval(x+17)) // 27
eval()还可以用来解析json
示例:
var data = "{a: '1',b: '2'}"
var obj = eval("("+data+")") // 转换为json
console.log(obj) // {a:'1',b:'2'}
此处将data用()括起来是由于json是以”{}”的方式来开始以及结束的,在JS中,它会被当成一个语句块来处理,所以必须
强制性的将它转换成一种表达式。
加上圆括号的目的是迫使eval函数在处理JavaScript代码的时候强制将括号内的表达式(expression)转化为对象,
而不是作为语 句(statement)来执行。举一个例子,例如对象字面量{},如若不加外层的括号,那么eval会将大括号
识别为JavaScript代码块的开始 和结束标记,那么{}将会被认为是执行了一句空语句。
看下面两个例子:
console.log(eval("{}"); // return undefined
console.log(eval("({})");// return object[Object]
注:虽然 eval() 的功能非常强大,但在实际使用中用到它的情况并不多。
(2)JSON.parse() 和JSON.stringify()
前者是将格式完好的json字符串转为json对象,所谓“格式完好”,就是要求json字符串必须严格符合JSON格式,属性名和
属性值必须用双引号,单引号只能用在{}外。
后者是将json对象转为字符串,在获取后台返回的数据时,经常会使json对象的格式,若直接打印此对象会出现
object Object,所以此时只需要使用JSON.stringify()转换一下即可看出json对象的数据。
示例:
var jsonStr = '{"a":"1","b":"2"}';
var obj = {a:"1",b:"2"};
console.log(JSON.parse(jsonStr)) // {"a":"1","b":"2"}
console.log(JSON.stringify(obj)) // {"a":"1","b":"2"}(此类型为string)
注:若jsonStr中有单引号导致JSON格式不对时,可将单引号转为双引号即可:
'{'a':'1','b':'2'}'.replace(/\'/g,'"')
7.检测升级
APP升级是一个很有必要的功能,在本次项目中升级的思路是:
① 首先检测后台的版本号与当前项目的版本号是否相同,如果相同则不升级,反之提示升级。
② 如果需要强制升级的话,则会将所有用户的状态清除,即使用户此时还在APP中,也会被强制退出提示升级。
升级代码演示:
checkVersionClick() {
var that = this
uni.request({
method:'GET',
url:'http:/xxx.xxx/getVersion/',
header: {
'Content-Type': 'application/json',
"Accept":"application/json",
},
success: (data) => {
if(data.statusCode === 200){
let version1 = plus.runtime.version
let version2 = eval('(' + data.data[0].description + ')').versionNum
if( version1 != version2){
if(eval('(' + data.data[0].description + ')').isForceUpdate == 1){
uni.showModal({ //提醒用户更新
title: "更新"+eval('(' + data.data[0].description + ')').versionNum+'提示',
confirmText:'立即升级',
cancelText:'退出APP',
showCancel:true,
content: eval("(" + data.data[0].description + ")").description,
success: (res) => {
if (res.confirm) {
that.isOnshowcheckVersion = true
plus.runtime.openURL(eval('(' + data.data[0].description + ')').pkgUrl);
// plus.runtime.restart();//下载后重启app
}else if(res.cancel){
uni.showModal({
title: '退出应用提示',
content: '是否退出大鲸智能?',
success: function(res) {
if (res.confirm) {
// 退出当前应用,改方法只在App中生效
plus.runtime.quit();
}else{
that.checkVersionClick()
that.isOnshowcheckVersion = true
}
}
});
}
}
})
}
}
}
}
})
},
升级设计的一些功能均是使用plus 5+ 的api做的点击此处查看官网。
5+的api用的不是很多,但是功能还是很强大的,有时间也需要多去研究研究哇。
8.uniapp打包
uniapp打包分为离线打包和在线打包。
离线打包即是使用Android studio以及官方SDK来进行打包,过程较为繁琐,有兴趣的同学可自行尝试点击此处查看详细过程。
在线打包也叫云打包,过程简单,方便,推荐使用,具体过程如下:点击查看文档
① 安装JRE环境,自行百度查看安装过程
② 生成签名证书:进入cmd后输入
keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore
(testalias是证书别名,可修改为自己想设置的字符,建议使用英文字母和数字;test.keystore是证书文件名称,可修改为自己想设置的文件名称)
回车后输入需要填写的内容即可生成证书,记住此证书的路径。
③ 查看证书:keytool -list -v -keystore test.keystore
输入密码后可看到证书的内容,此证书的MD5的指纹信息即为申请Andorid应用的应用签名,这两者必须匹配,否则上线可能会失败。
④ 在hx中点击发行-->原生APP-云打包-->填写包名,选择使用自有证书(此处的证书即为刚刚生成的证书),填写证书别名、私钥密码和文件路径。
渠道包是用于对应APP上线的应用商店,需要上线哪个应用商店就选择对应的渠道包。
若只是测试第三方SDK只需要点击自定义基座就可以了。
注:微信支付必须使用自定义基座,打包后才可以测试!!!
好哒~今天的总结先到这里了,之后有新的问题再更新啦,欢迎各位小可爱的留言哦!