
HBuilder调用微信支付功能
1.用户申请微信开放平台申请移动应用
ps:移动应用申请时包名必须与打包app包名相同,
签名需要通过java的keytool工具去生成md5签名(注意微信使用的是md5签名) java的版本为jdk-6u43-windows
高版本的工具只能生成SHA1和SHA256这俩个微信支付用不了
<script type="text/javascript">
var pays = {};
var PAYSERVER = null;
function plusReady() {
let self = plus.webview.currentWebview();
let [waybill_sn, waybill_id] = [self.waybill_sn, self.waybill_id];
console.log(waybill_sn)
console.log(waybill_id)
// 获取支付通道
plus.payment.getChannels(function(channels) {
var content = document.getElementById('dcontent');
var info = document.getElementById('info');
var txt = '支付通道信息:';
for(var i in channels) {
var channel = channels[i];
if(channel.id == 'qhpay' || channel.id == 'qihoo') { // 过滤掉不支持的支付通道:暂不支持360相关支付
continue;
}
pays[channel.id] = channel;
txt += 'id:' + channel.id + ', ';
txt += 'description:' + channel.description + ', ';
txt += 'serviceReady:' + channel.serviceReady + '; ';
var de = document.createElement('div');
de.setAttribute('class', 'button');
de.setAttribute('onclick', 'pay(this.id)');
de.id = channel.id;
de.innerText = channel.description + '支付';
content.appendChild(de);
checkServices(channel);
}
info.innerText = txt;
}, function(e) {
ddsd.log('获取支付通道失败:' + e.message);
});
PAYSERVER = ddsd.ddsdAjax + 'Waybill/getWaybillPayInfo?id='+waybill_id+'&session3rd='+ddsd.session3rd()+'&waybill_sn='+waybill_sn+'&setTradeType=app&payid=WxPay'
}
document.addEventListener('plusready', plusReady, false);
// 检测是否安装支付服务
function checkServices(pc) {
if(!pc.serviceReady) {
var txt = null;
switch(pc.id) {
case 'alipay':
txt = '检测到系统未安装“支付宝快捷支付服务”,无法完成支付操作,是否立即安装?';
break;
default:
txt = '系统未安装“' + pc.description + '”服务,无法完成支付,是否立即安装?';
break;
}
plus.nativeUI.confirm(txt, function(e) {
if(e.index == 0) {
pc.installService();
}
}, pc.description);
}
}
var w = null;
function pay(id) {
if(w) {
return;
}
ddsd.log('----- 请求支付 -----');
var url = PAYSERVER;
var appid = plus.runtime.appid;//此处的appid为应用包的appid 真机调试永远为HBuilder打包后为该应用真实包名
if(navigator.userAgent.indexOf('StreamApp') >= 0) {
appid = 'Stream';
}
url += '&appid='+ appid +'&total=0.01';
w = plus.nativeUI.showWaiting();
// 请求支付订单
var amount = document.getElementById('total').value;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch(xhr.readyState) {
case 4:
w.close();
w = null;
if(xhr.status == 200) {
ddsd.log('----- 请求订单成功 -----');
var order = xhr.responseText
plus.payment.request(pays[id], order, function(result) {
ddsd.log('----- 支付成功 -----');
plus.nativeUI.alert('支付成功:感谢你的支持,我们会继续努力完善产品。', function() {
back();
}, '捐赠');
}, function(e) {
ddsd.log('----- 支付失败 -----');
plus.nativeUI.alert('更多错误信息请参考支付(Payment)规范文档:http://www.html5plus.org/#specification#/specification/Payment.html', null, '支付失败:' + e.code);
});
} else {
ddsd.log('----- 请求订单失败 -----');
plus.nativeUI.alert('获取订单信息失败!', null, '捐赠');
}
break;
default:
break;
}
}
xhr.open('GET', url );
ddsd.log('请求支付订单:' + url);
xhr.send();
}
</script>
请求url
http://ddsd2.ittun.com/worker.php/Waybill/getWaybillPayInfo?id=1054996865944260608&session3rd=session5bd01de5290cd&waybill_sn=1540682647330&setTradeType=app&payid=WxPay&appid=HBuilder&total=0.01
开始打包
包名必须和微信开放平台相同
证书别名为申请密钥使用的别名
密码为申请秘钥的密码
文件为申请后的证书文件
申请秘钥步骤为
1.下载1.6版本java
2.进入jdk下bin 使用
keytool -genkey -alias xxx -keyalg RSA -keysize 1024 -keypass ddsd123456 -validity 3500 -keystore c:\key\xxx.keystore
创建密钥
3.keytool -list -v -keystore c:\key\xxx.keystore
使用当前命令查看密钥信息
最要的一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行
最重要的一定要把微信缓存清理一下 不行就卸了重装 缓存是个坑 记得清缓存 记得清缓存 记得清缓存 记得清缓存
还有不懂的邮箱是我qq 1035355110
1.用户申请微信开放平台申请移动应用
ps:移动应用申请时包名必须与打包app包名相同,
签名需要通过java的keytool工具去生成md5签名(注意微信使用的是md5签名) java的版本为jdk-6u43-windows
高版本的工具只能生成SHA1和SHA256这俩个微信支付用不了
<script type="text/javascript">
var pays = {};
var PAYSERVER = null;
function plusReady() {
let self = plus.webview.currentWebview();
let [waybill_sn, waybill_id] = [self.waybill_sn, self.waybill_id];
console.log(waybill_sn)
console.log(waybill_id)
// 获取支付通道
plus.payment.getChannels(function(channels) {
var content = document.getElementById('dcontent');
var info = document.getElementById('info');
var txt = '支付通道信息:';
for(var i in channels) {
var channel = channels[i];
if(channel.id == 'qhpay' || channel.id == 'qihoo') { // 过滤掉不支持的支付通道:暂不支持360相关支付
continue;
}
pays[channel.id] = channel;
txt += 'id:' + channel.id + ', ';
txt += 'description:' + channel.description + ', ';
txt += 'serviceReady:' + channel.serviceReady + '; ';
var de = document.createElement('div');
de.setAttribute('class', 'button');
de.setAttribute('onclick', 'pay(this.id)');
de.id = channel.id;
de.innerText = channel.description + '支付';
content.appendChild(de);
checkServices(channel);
}
info.innerText = txt;
}, function(e) {
ddsd.log('获取支付通道失败:' + e.message);
});
PAYSERVER = ddsd.ddsdAjax + 'Waybill/getWaybillPayInfo?id='+waybill_id+'&session3rd='+ddsd.session3rd()+'&waybill_sn='+waybill_sn+'&setTradeType=app&payid=WxPay'
}
document.addEventListener('plusready', plusReady, false);
// 检测是否安装支付服务
function checkServices(pc) {
if(!pc.serviceReady) {
var txt = null;
switch(pc.id) {
case 'alipay':
txt = '检测到系统未安装“支付宝快捷支付服务”,无法完成支付操作,是否立即安装?';
break;
default:
txt = '系统未安装“' + pc.description + '”服务,无法完成支付,是否立即安装?';
break;
}
plus.nativeUI.confirm(txt, function(e) {
if(e.index == 0) {
pc.installService();
}
}, pc.description);
}
}
var w = null;
function pay(id) {
if(w) {
return;
}
ddsd.log('----- 请求支付 -----');
var url = PAYSERVER;
var appid = plus.runtime.appid;//此处的appid为应用包的appid 真机调试永远为HBuilder打包后为该应用真实包名
if(navigator.userAgent.indexOf('StreamApp') >= 0) {
appid = 'Stream';
}
url += '&appid='+ appid +'&total=0.01';
w = plus.nativeUI.showWaiting();
// 请求支付订单
var amount = document.getElementById('total').value;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch(xhr.readyState) {
case 4:
w.close();
w = null;
if(xhr.status == 200) {
ddsd.log('----- 请求订单成功 -----');
var order = xhr.responseText
plus.payment.request(pays[id], order, function(result) {
ddsd.log('----- 支付成功 -----');
plus.nativeUI.alert('支付成功:感谢你的支持,我们会继续努力完善产品。', function() {
back();
}, '捐赠');
}, function(e) {
ddsd.log('----- 支付失败 -----');
plus.nativeUI.alert('更多错误信息请参考支付(Payment)规范文档:http://www.html5plus.org/#specification#/specification/Payment.html', null, '支付失败:' + e.code);
});
} else {
ddsd.log('----- 请求订单失败 -----');
plus.nativeUI.alert('获取订单信息失败!', null, '捐赠');
}
break;
default:
break;
}
}
xhr.open('GET', url );
ddsd.log('请求支付订单:' + url);
xhr.send();
}
</script>
请求url
http://ddsd2.ittun.com/worker.php/Waybill/getWaybillPayInfo?id=1054996865944260608&session3rd=session5bd01de5290cd&waybill_sn=1540682647330&setTradeType=app&payid=WxPay&appid=HBuilder&total=0.01
开始打包
包名必须和微信开放平台相同
证书别名为申请密钥使用的别名
密码为申请秘钥的密码
文件为申请后的证书文件
申请秘钥步骤为
1.下载1.6版本java
2.进入jdk下bin 使用
keytool -genkey -alias xxx -keyalg RSA -keysize 1024 -keypass ddsd123456 -validity 3500 -keystore c:\key\xxx.keystore
创建密钥
3.keytool -list -v -keystore c:\key\xxx.keystore
使用当前命令查看密钥信息
最要的一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行 一定要真机运行
最重要的一定要把微信缓存清理一下 不行就卸了重装 缓存是个坑 记得清缓存 记得清缓存 记得清缓存 记得清缓存
还有不懂的邮箱是我qq 1035355110
收起阅读 »
个推
1.我相信开始使用推送的小伙伴,都是使用登录个推的平台上,发送推送测试,发现普通的推送没有问题,透传多多少少都是有点问题.,透传不会触发.
2.然后呢,用我们的后台来推送时,我们是希望后台把消息发送来,出现在通知栏,然后点击通知栏,拿到后台的数据,跳转到指定页面
- 这里说一下,后台是有模板的(两种),他发送的数据,可以选择1.点击通知触发,2.直接触发receive模板.(这是后台来决定的)
- 我的需求是有些通知需要点击通知栏,有一些更新操作,需要直接触发receive,静默更新操作.所以,我就让后台区分一下,该用模板1就用模板1,用模板2就用模板2
- 为什么要说这个,因为我的后台开始不知道还有其他模板,他就是会用推送时,点击通知栏获取.不会用直接触发app的receive监听函数.还是我去找个推客服解决的.又是坑
1.我相信开始使用推送的小伙伴,都是使用登录个推的平台上,发送推送测试,发现普通的推送没有问题,透传多多少少都是有点问题.,透传不会触发.
2.然后呢,用我们的后台来推送时,我们是希望后台把消息发送来,出现在通知栏,然后点击通知栏,拿到后台的数据,跳转到指定页面
- 这里说一下,后台是有模板的(两种),他发送的数据,可以选择1.点击通知触发,2.直接触发receive模板.(这是后台来决定的)
- 我的需求是有些通知需要点击通知栏,有一些更新操作,需要直接触发receive,静默更新操作.所以,我就让后台区分一下,该用模板1就用模板1,用模板2就用模板2
- 为什么要说这个,因为我的后台开始不知道还有其他模板,他就是会用推送时,点击通知栏获取.不会用直接触发app的receive监听函数.还是我去找个推客服解决的.又是坑

vant 使用心得
强调下这个组件是app和微信小程序通用,但不能用于h5、其他小程序
官方更新很久支持 小程序的组件了。文档介绍地址: http://uniapp.dcloud.io/
vant 官方文档:
https://youzan.github.io/vant-weapp
怎么使用昵?
安装方式支持npm git 。还有一个方式是直接去 git clone 传送门:https://github.com/youzan/vant-weapp
下载后 把压缩文件解压,看到根目录有一个 dist 的目录,将整个目录拷贝下来。
然后在你的UNI 的项目根目录创建文件: wxcomponents/vant ,将你上面拷贝的 dist 目录的内容粘贴到 项目根目录 wxcomponents/vant 下。
然后打开你项目根目录的 pages.json 在每个页面的 style 下 创建一个 usingComponent (这块就请看UNI的官方文档吧!)
例如:
"usingComponents" : {
"van-search": "/wxcomponents/vant/dist/search/index"
}
创建后 打开page.vue 页面。 使用组件 (每个组件使用的方式都不一样 这点可以去vant官网查看!)
<van-search :value="value" placeholder="请输入搜索关键词" show-action @search="onSearch" @cancel="onCancel"></van-search>
值得一说的是 vant 提供的方式代码是 :
<van-search
value="{{ value }}"
placeholder="请输入搜索关键词"
show-action
bind:search="onSearch"
bind:cancel="onCancel"
/>
在UNI 下需要做一些修改:
1.绑定的变量使用 :value="value"
- bind:search 更改为 @search="onSearch" ; 就是把 bind: 换成 @ 即可。
更改后的例子:
<van-search :value="value" placeholder="请输入搜索关键词" show-action @search="onSearch" @cancel="onCancel"></van-search>
特别要说明的是:每次修改 page.vue 中的节点以后 保存后不会直接生效,你得点重新运行(控制台右上角有一个类似刷新的图标)
vant weapp用于app时,在低端Android上有css兼容性问题要注意。因为app的webview和微信不一样,app是系统webview。Android5以下的webview版本较低,有些较新的css不支持。
强调下这个组件是app和微信小程序通用,但不能用于h5、其他小程序
官方更新很久支持 小程序的组件了。文档介绍地址: http://uniapp.dcloud.io/
vant 官方文档:
https://youzan.github.io/vant-weapp
怎么使用昵?
安装方式支持npm git 。还有一个方式是直接去 git clone 传送门:https://github.com/youzan/vant-weapp
下载后 把压缩文件解压,看到根目录有一个 dist 的目录,将整个目录拷贝下来。
然后在你的UNI 的项目根目录创建文件: wxcomponents/vant ,将你上面拷贝的 dist 目录的内容粘贴到 项目根目录 wxcomponents/vant 下。
然后打开你项目根目录的 pages.json 在每个页面的 style 下 创建一个 usingComponent (这块就请看UNI的官方文档吧!)
例如:
"usingComponents" : {
"van-search": "/wxcomponents/vant/dist/search/index"
}
创建后 打开page.vue 页面。 使用组件 (每个组件使用的方式都不一样 这点可以去vant官网查看!)
<van-search :value="value" placeholder="请输入搜索关键词" show-action @search="onSearch" @cancel="onCancel"></van-search>
值得一说的是 vant 提供的方式代码是 :
<van-search
value="{{ value }}"
placeholder="请输入搜索关键词"
show-action
bind:search="onSearch"
bind:cancel="onCancel"
/>
在UNI 下需要做一些修改:
1.绑定的变量使用 :value="value"
- bind:search 更改为 @search="onSearch" ; 就是把 bind: 换成 @ 即可。
更改后的例子:
<van-search :value="value" placeholder="请输入搜索关键词" show-action @search="onSearch" @cancel="onCancel"></van-search>
特别要说明的是:每次修改 page.vue 中的节点以后 保存后不会直接生效,你得点重新运行(控制台右上角有一个类似刷新的图标)
vant weapp用于app时,在低端Android上有css兼容性问题要注意。因为app的webview和微信不一样,app是系统webview。Android5以下的webview版本较低,有些较新的css不支持。
收起阅读 »
一周 D 报(2018-10-24)
本周的 D 报来的晚了一些,但来的早不如来的巧,今天是属于各位程序员同学的节日 1024。
在此节日期间,DCloud 也为大家送上一份大礼。那就是,uni-app 官方视频教程:https://ke.qq.com/course/343370。
为了更加方便观看教程,可以加入 uni-app QQ 群,直接点击课堂即可。
- uni-app 1群:531031261(已满)
- uni-app 2群:901474938(已满)
- uni-app 3群:773794803(期待你的加入)
uni-app
- rich-text 里面的节点样式怎么控制? 两种思路,一种是生成富文本时就处理好,另一种就是在 nodes 中设置节点的 style 或者 class 来处理。
- 使用nvue页面不能生成小程序吗? nvue 是 App 平台的强化,并不属于小程序的规范。
- uni-app 可以直接改变元素的 css 吗? uni-app 中没有 DOM 的操作,因此实现的思路是点击之后修改相关的计算属性来动态调整样式。
- v-for 中必须声明 key Vue 的规范是推荐声明 key,uni-app 做了强制约定。
- uni-app 有退出接口么? 详见这篇文档 uni-app 中退出应用。
- 小程序里是有50ms的请求间隔限制,打包成App也有吗? 目前同样存在此限制,后面酌情考虑调整。
- uni-app ios目前在app store可以审核通过吗:可以下载案例中的应用体验。
nvue
uni-app 在 App 平台下提供了 nvue,实现了 App 端页面的原生渲染进一步提高页面的流畅性。
- 详细的文档参考:在 uni-app 中使用 Weex
- 参考示例:hello uni-app->模板->选项卡->原生
H5+
开源与分享
- DCloud 官方出品的 uni-app 教程,已经在腾讯课堂开课了,免费的哦。欢迎大家参与学习,并且提出你宝贵的意见。
- 近期又有许多 uni-app 开发的应用顺利上线了,欢迎大家下载体验,也希望大家踊跃向 DCloud 提交更多案例。
欢迎更多的同学参与进来,分享自己的经验心得。
结束
本期周报就到这里,感谢大家的阅读。新的一周,祝大家工作顺利。
本周的 D 报来的晚了一些,但来的早不如来的巧,今天是属于各位程序员同学的节日 1024。
在此节日期间,DCloud 也为大家送上一份大礼。那就是,uni-app 官方视频教程:https://ke.qq.com/course/343370。
为了更加方便观看教程,可以加入 uni-app QQ 群,直接点击课堂即可。
- uni-app 1群:531031261(已满)
- uni-app 2群:901474938(已满)
- uni-app 3群:773794803(期待你的加入)
uni-app
- rich-text 里面的节点样式怎么控制? 两种思路,一种是生成富文本时就处理好,另一种就是在 nodes 中设置节点的 style 或者 class 来处理。
- 使用nvue页面不能生成小程序吗? nvue 是 App 平台的强化,并不属于小程序的规范。
- uni-app 可以直接改变元素的 css 吗? uni-app 中没有 DOM 的操作,因此实现的思路是点击之后修改相关的计算属性来动态调整样式。
- v-for 中必须声明 key Vue 的规范是推荐声明 key,uni-app 做了强制约定。
- uni-app 有退出接口么? 详见这篇文档 uni-app 中退出应用。
- 小程序里是有50ms的请求间隔限制,打包成App也有吗? 目前同样存在此限制,后面酌情考虑调整。
- uni-app ios目前在app store可以审核通过吗:可以下载案例中的应用体验。
nvue
uni-app 在 App 平台下提供了 nvue,实现了 App 端页面的原生渲染进一步提高页面的流畅性。
- 详细的文档参考:在 uni-app 中使用 Weex
- 参考示例:hello uni-app->模板->选项卡->原生
H5+
开源与分享
- DCloud 官方出品的 uni-app 教程,已经在腾讯课堂开课了,免费的哦。欢迎大家参与学习,并且提出你宝贵的意见。
- 近期又有许多 uni-app 开发的应用顺利上线了,欢迎大家下载体验,也希望大家踊跃向 DCloud 提交更多案例。
欢迎更多的同学参与进来,分享自己的经验心得。
结束
本期周报就到这里,感谢大家的阅读。新的一周,祝大家工作顺利。

在 5+ App 更加优雅地控制下拉刷新的开关
Webview 对象的 setPullToRefresh 方法将会被废弃,使用新的 API 来控制下拉刷新的开关。
var webview = plus.webview.currentWebview();
// 开启下拉刷新功能
webview.setStyle({
pullToRefresh: {
support: true //关闭下拉刷新的话,把这里设置为 false。
}
});
// 监听下拉刷新事件,关闭的情况下不会触发该事件。
webview.addEventListener('pullToRefresh', function() {
// 这里可执行从服务器获取数据刷新业务逻辑
setTimeout(function() {
// 完成刷新逻辑后调用endPullToRefresh退出刷新状态
plus.nativeUI.toast('更新完成!');
webview.endPullToRefresh();
}, 5000);
}, false);
下拉刷新的开关与事件的监听,是分开的,开启/关闭下拉刷新只需要通过 setStyle 来调整即可,不用每次都设置下拉的回调函数。
Webview 对象的 setPullToRefresh 方法将会被废弃,使用新的 API 来控制下拉刷新的开关。
var webview = plus.webview.currentWebview();
// 开启下拉刷新功能
webview.setStyle({
pullToRefresh: {
support: true //关闭下拉刷新的话,把这里设置为 false。
}
});
// 监听下拉刷新事件,关闭的情况下不会触发该事件。
webview.addEventListener('pullToRefresh', function() {
// 这里可执行从服务器获取数据刷新业务逻辑
setTimeout(function() {
// 完成刷新逻辑后调用endPullToRefresh退出刷新状态
plus.nativeUI.toast('更新完成!');
webview.endPullToRefresh();
}, 5000);
}, false);
下拉刷新的开关与事件的监听,是分开的,开启/关闭下拉刷新只需要通过 setStyle 来调整即可,不用每次都设置下拉的回调函数。
收起阅读 »
uni-app 中退出应用
在 App 环境下,可以直接调用 5+ API 来实现。
// #ifdef APP-PLUS
plus.runtime.quit();
// #endif
注意:iOS 平台不支持此 API,只能是用户主动杀进程。
微信小程序平台下,2.1.0 版本开始,navigate 支持设置 open-type 为 exit 来退出。
<navigator target="miniProgram" open-type="exit">退出小程序</navigator>
在 App 环境下,可以直接调用 5+ API 来实现。
// #ifdef APP-PLUS
plus.runtime.quit();
// #endif
注意:iOS 平台不支持此 API,只能是用户主动杀进程。
微信小程序平台下,2.1.0 版本开始,navigate 支持设置 open-type 为 exit 来退出。
<navigator target="miniProgram" open-type="exit">退出小程序</navigator>
收起阅读 »

Android开发中XRecyclerview用法及遇到的一些问题
目前通过xrecyclerview的开源代码来实现系列功能,加载数据传入type,值为1,2,3,分别表示初次加载,下拉刷新数据,上拉加载更多数据操作,刷新数据只需要重新放入数据,然后notifyDataSetChanged();即可.加载更多数据只需要在上拉时将获取数据放入之前数据list中刷新数据即可.这么说可能会比较抽象,下面通过代码来具体给大家演示一下是如何实现的吧。
核心代码:
首先需要配置xRecyclerview的属性:
xRecyclerView.setPullRefreshEnabled(true);
xRecyclerView.setLoadingMoreEnabled(true);
xRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);
xRecyclerView.setLoadingMoreProgressStyle(ProgressStyle.Pacman);
xRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable(){
public void run() {
getWorksData(1,2);
}
}, 2000);
}
@Override
public void onLoadMore() {
count+=1;
loge("第几次加载=="+count);
new Handler().postDelayed(new Runnable(){
public void run() {
getWorksData(count,3);
}
}, 2000);
}
});
从上面代码可以看到,需要先设置下拉刷新和加载更多可执行,为true,然后设置它的加载样式,有多种样式可以选择,具体参考xrecyclerview的github介绍,接下里设置一下loadingListener即可.我们需要实现它的两个方法:刷新回调方法onRefresh()和加载更多方法onLoadingMore(),即分别在这两个方法中实现自己的刷新和加载数据逻辑即可.
getWorksData(参数1,参数2)即为获取后天数据的方法.参数1是指数据请求的次数,也指代请求后台的数据页数,初始化为1;参数2表示当前数据的操作模式(为1:初次请求数据,为2:刷新数据,为3:加载更多数据).
loadingDialog.dismiss();
creativeImageBean = JSONObject.parseObject(response, CreativeImageBean.class);
if (creativeImageBean!=null && creativeImageBean.getCode() == 1000) {
if(type==1){
//是初次加载
loge("初次加载数据");
data=creativeImageBean.getData().getList();
Message msg = Message.obtain(handler);
msg.what = GET_DATA;
handler.handleMessage(msg);
}else if(type==2){
//下拉刷新
//data = new ArrayList();
updateData=creativeImageBean.getData().getList();
count = 1;
loge("刷新了");
xRecyclerView.refreshComplete();
if (workAdapter != null) {
Message msg = Message.obtain(handler);
msg.what = UPDATE_DATA;
handler.sendMessage(msg);
} else {
Message msg = Message.obtain(handler);
msg.what = GET_DATA;
handler.sendMessage(msg);
}
}else if(type==3){
//加载更多
//moreData = new ArrayList();
moreData = creativeImageBean.getData().getList();
loge("加载更多数据页数==" + count+"---数据量--"+moreData.size());
if (moreData != null && moreData.size() > 0) {
data.addAll(moreData);
loge("data加载更多数据后的地址=="+data.hashCode());
loge("作品总数据长度==" + data.size());
// Message msg = Message.obtain(handler);
// msg.what = UPDATE_DATA;
// handler.sendMessage(msg);
if(workAdapter!=null){
loge("workAdapter不为空");
workAdapter.notifyDataSetChanged();
}else {
loge("workAdapter为空");
workAdapter = new WorksShowAdapter(MemoryWorksActivity.this,data);
xRecyclerView.setAdapter(workAdapter);
}
xRecyclerView.loadMoreComplete();
//workAdapter.addNewData(data);//添加数据
//如果添加moreData,为空是什么原因
} else {
loge("moreData数据为空");
// xRecyclerView.setLoadingMoreEnabled(false);
// toast(getString(R.string.act_home_loadmore));
xRecyclerView.loadMoreComplete();
}
}
}
刷新数据需要先清除原有数据,然后放入最新数据,接着调用adaper.motifyDataSetChange()方法.
问题总览
点击第i个item,提示却是第i+1个item被点击
问题原因:xrecyclerrview默认添加的header和footer,这就导致item的真实位置发生了变化,
解决方案:将item的位置由holder.getLayoutPosition()改为position就可以了,adapter中修改代码如下:
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//int pos = holder.getLayoutPosition();//点击的item控件的位置
myListener.onItemClick(holder.itemView, position);
/*
此方法返回的pos值与onBindViewHolder方法传入的position值有可能不同。
根据SDK中的解释,在Recyclerview 进行添加、移除item等操作时,position位置可能会变化,
而所有的adapter的刷新并不总是及时的,
只有这个方法返回的才是当前item经过一些变换后所处的真正位置。
*/
}
});
notifySetDataCahnged()无法刷新数据的问题:
问题原因:先下拉刷新,然后上拉加载数据为空不显示,因为data的地址发生了变化,数据的刷新是在adapter中实现的,并且是新建一个list,然后调用了list.addAll(data),导致刷新data数据地址改变,刷新无效
解决方案:新建一个list对象moreData来专门接收下拉刷新的数据,并且摒弃adapter中的addNewData()方法,直接data.clear()—data.addAll(moreData)—adapter.notifyDataChanged()
虽然内容有些多,但是只要大家按照刚才分享的源码来一步一步的去做,都是可以做到的,如果还是存在不理解的地方,可以咨询我们哦。
本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明原文作者及出处。
目前通过xrecyclerview的开源代码来实现系列功能,加载数据传入type,值为1,2,3,分别表示初次加载,下拉刷新数据,上拉加载更多数据操作,刷新数据只需要重新放入数据,然后notifyDataSetChanged();即可.加载更多数据只需要在上拉时将获取数据放入之前数据list中刷新数据即可.这么说可能会比较抽象,下面通过代码来具体给大家演示一下是如何实现的吧。
核心代码:
首先需要配置xRecyclerview的属性:
xRecyclerView.setPullRefreshEnabled(true);
xRecyclerView.setLoadingMoreEnabled(true);
xRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);
xRecyclerView.setLoadingMoreProgressStyle(ProgressStyle.Pacman);
xRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable(){
public void run() {
getWorksData(1,2);
}
}, 2000);
}
@Override
public void onLoadMore() {
count+=1;
loge("第几次加载=="+count);
new Handler().postDelayed(new Runnable(){
public void run() {
getWorksData(count,3);
}
}, 2000);
}
});
从上面代码可以看到,需要先设置下拉刷新和加载更多可执行,为true,然后设置它的加载样式,有多种样式可以选择,具体参考xrecyclerview的github介绍,接下里设置一下loadingListener即可.我们需要实现它的两个方法:刷新回调方法onRefresh()和加载更多方法onLoadingMore(),即分别在这两个方法中实现自己的刷新和加载数据逻辑即可.
getWorksData(参数1,参数2)即为获取后天数据的方法.参数1是指数据请求的次数,也指代请求后台的数据页数,初始化为1;参数2表示当前数据的操作模式(为1:初次请求数据,为2:刷新数据,为3:加载更多数据).
loadingDialog.dismiss();
creativeImageBean = JSONObject.parseObject(response, CreativeImageBean.class);
if (creativeImageBean!=null && creativeImageBean.getCode() == 1000) {
if(type==1){
//是初次加载
loge("初次加载数据");
data=creativeImageBean.getData().getList();
Message msg = Message.obtain(handler);
msg.what = GET_DATA;
handler.handleMessage(msg);
}else if(type==2){
//下拉刷新
//data = new ArrayList();
updateData=creativeImageBean.getData().getList();
count = 1;
loge("刷新了");
xRecyclerView.refreshComplete();
if (workAdapter != null) {
Message msg = Message.obtain(handler);
msg.what = UPDATE_DATA;
handler.sendMessage(msg);
} else {
Message msg = Message.obtain(handler);
msg.what = GET_DATA;
handler.sendMessage(msg);
}
}else if(type==3){
//加载更多
//moreData = new ArrayList();
moreData = creativeImageBean.getData().getList();
loge("加载更多数据页数==" + count+"---数据量--"+moreData.size());
if (moreData != null && moreData.size() > 0) {
data.addAll(moreData);
loge("data加载更多数据后的地址=="+data.hashCode());
loge("作品总数据长度==" + data.size());
// Message msg = Message.obtain(handler);
// msg.what = UPDATE_DATA;
// handler.sendMessage(msg);
if(workAdapter!=null){
loge("workAdapter不为空");
workAdapter.notifyDataSetChanged();
}else {
loge("workAdapter为空");
workAdapter = new WorksShowAdapter(MemoryWorksActivity.this,data);
xRecyclerView.setAdapter(workAdapter);
}
xRecyclerView.loadMoreComplete();
//workAdapter.addNewData(data);//添加数据
//如果添加moreData,为空是什么原因
} else {
loge("moreData数据为空");
// xRecyclerView.setLoadingMoreEnabled(false);
// toast(getString(R.string.act_home_loadmore));
xRecyclerView.loadMoreComplete();
}
}
}
刷新数据需要先清除原有数据,然后放入最新数据,接着调用adaper.motifyDataSetChange()方法.
问题总览
点击第i个item,提示却是第i+1个item被点击
问题原因:xrecyclerrview默认添加的header和footer,这就导致item的真实位置发生了变化,
解决方案:将item的位置由holder.getLayoutPosition()改为position就可以了,adapter中修改代码如下:
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//int pos = holder.getLayoutPosition();//点击的item控件的位置
myListener.onItemClick(holder.itemView, position);
/*
此方法返回的pos值与onBindViewHolder方法传入的position值有可能不同。
根据SDK中的解释,在Recyclerview 进行添加、移除item等操作时,position位置可能会变化,
而所有的adapter的刷新并不总是及时的,
只有这个方法返回的才是当前item经过一些变换后所处的真正位置。
*/
}
});
notifySetDataCahnged()无法刷新数据的问题:
问题原因:先下拉刷新,然后上拉加载数据为空不显示,因为data的地址发生了变化,数据的刷新是在adapter中实现的,并且是新建一个list,然后调用了list.addAll(data),导致刷新data数据地址改变,刷新无效
解决方案:新建一个list对象moreData来专门接收下拉刷新的数据,并且摒弃adapter中的addNewData()方法,直接data.clear()—data.addAll(moreData)—adapter.notifyDataChanged()
虽然内容有些多,但是只要大家按照刚才分享的源码来一步一步的去做,都是可以做到的,如果还是存在不理解的地方,可以咨询我们哦。
本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明原文作者及出处。
收起阅读 »
拍照后获取图片的宽,高,大小等信息
plus.camera.getCamera().captureImage(function(absPath) {
//创建一个 bitmap 对象,参数1是id,参数2是拍照返回的图片绝对路径
var bitmap = new plus.nativeObj.Bitmap('test', absPath);
//没办法,费点事,再用 bitmap 保存一下,overwrite 属性表示是否覆盖原来文件,第1个回调是保存成功,第2个回调是保存失败
bitmap.save(
absPath,
{
overwrite: true,
format: 'jpg',
},
function(event) {
// Code here
// 保存后的图片url路径,以"file://"开头
var target = event.target;
// 保存后图片的大小,单位为字节(Byte)
var size = event.size;
// 保存后图片的实际宽度,单位为px
var width = event.width;
// 保存后图片的实际高度,单位为px
var height = event.height;
console.log('图片绝对路径: ' + target)
console.log('图片文件大小:' + size)
console.log('图片宽度:' + width)
console.log('图片高度:' + height)
function bytesToSize(bytes) {
if (bytes === 0) {
return '0 B'
}
var k = 1000, // or 1024
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
}
var ss = bytesToSize(size);
console.log(ss)
},
function(error) {
// Error.
var code = error.code; // 错误编码
var message = error.message; // 错误描述信息
console.log(code)
console.log(message)
}
);
}
其实我觉得 new plus.nativeObj.Bitmap('test', absPath) 后就应该包含了该有的信息了....
plus.camera.getCamera().captureImage(function(absPath) {
//创建一个 bitmap 对象,参数1是id,参数2是拍照返回的图片绝对路径
var bitmap = new plus.nativeObj.Bitmap('test', absPath);
//没办法,费点事,再用 bitmap 保存一下,overwrite 属性表示是否覆盖原来文件,第1个回调是保存成功,第2个回调是保存失败
bitmap.save(
absPath,
{
overwrite: true,
format: 'jpg',
},
function(event) {
// Code here
// 保存后的图片url路径,以"file://"开头
var target = event.target;
// 保存后图片的大小,单位为字节(Byte)
var size = event.size;
// 保存后图片的实际宽度,单位为px
var width = event.width;
// 保存后图片的实际高度,单位为px
var height = event.height;
console.log('图片绝对路径: ' + target)
console.log('图片文件大小:' + size)
console.log('图片宽度:' + width)
console.log('图片高度:' + height)
function bytesToSize(bytes) {
if (bytes === 0) {
return '0 B'
}
var k = 1000, // or 1024
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
}
var ss = bytesToSize(size);
console.log(ss)
},
function(error) {
// Error.
var code = error.code; // 错误编码
var message = error.message; // 错误描述信息
console.log(code)
console.log(message)
}
);
}
其实我觉得 new plus.nativeObj.Bitmap('test', absPath) 后就应该包含了该有的信息了....
收起阅读 »
HTML中JS对于字符串的切割截取实现
在网站编程制作中,对于字符串的切割截取平时所用可能不是特别多,而且分的比较细,所以自备自查。有备无患。由于之前所有均在一个demo测试,下面就来跟大家分享一下成果。
1.函数:split()
功能:使用一个指定的分隔符把一个字符串分割存储到数组
例子: str=”jpg|bmp|gif|ico|png”; arr=str.split(”|”);
//arr是一个包含字符值”jpg”、”bmp”、”gif”、”ico”和”png”的数组
2.函数:join()
功能:使用您选择的分隔符将一个数组合并为一个字符串
例子: var delimitedString=myArray.join(delimiter);
var myList=new Array(”jpg”,”bmp”,”gif”,”ico”,”png”);
var portableList=myList.join(”|”);
//结果是jpg|bmp|gif|ico|png
3.函数:concat()
功能:将两个数组连接在一起;
例子:arr1=[1,2,3,4]
arr2=[5,6,7,8]
alert(arr1.concat(arr2)) //结果为[1,2,3,4,5,6,7,8]
4.函数:charAt()
功能:返回指定位置的字符。字符串中第一个字符的下标是 0。如果参数 index 不在 0 与 string.length 之间,该方法将返回一个空字符串。
例子:var str='a,g,i,d,o,v,w,d,k,p'
alert(str.charAt(2)) //结果为g
5:函数:charCodeAt()
功能:charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
方法 charCodeAt() 与 charAt() 方法执行的操作相似,只不过前者返回的是位于指定位置的字符的编码,而后者返回的是字符子串。
例子:var str='a,g,i,d,o,v,w,d,k,p'
alert(str.charCodeAt(2)) //结果为103。即g的Unicode编码为103
6.函数:slice()
功能:arrayObject.slice(start,end)
start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end:可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
返回一个新的数组,包含从start到end(不包括该元素)的arrayobject中的元素。
例子:var str='ahji3o3s4e6p8a0sdewqdasj'
alert(str.slice(2,5)) //结果ji3
7.函数:substring()
定义和用法 substring 方法用于提取字符串中介于两个指定下标之间的字符。
语法 stringObject.substring(start,stop)
start 必需。一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置。
stop 可选。一个非负的整数,比要提取的子串的最后一个字符在 stringObject 中的位置多 1。
如果省略该参数,那么返回的子串会一直到字符串的结尾。
返回 一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 start 处到 stop-1 处的所有字符,其长度为 stop 减 start。 说明 substring 方法返回的子串包括 start 处的字符,但不包括 end 处的字符。 如果 start 与 end 相等,那么该方法返回的就是一个空串(即长度为 0 的字符串)。 如果 start 比 end 大,那么该方法在提取子串之前会先交换这两个参数。 如果 start 或 end 为负数,那么它将被替换为 0。
例子:var str='ahji3o3s4e6p8a0sdewqdasj'
alert(str.substring(2,6)) //结果为ji3o3
8.函数:substr
定义和用法 substr 方法用于返回一个从指定位置开始的指定长度的子字符串。
语法 stringObject.substr(start [, length ])
参数 start 必需。所需的子字符串的起始位置。字符串中的第一个字符的索引为 0。
length 可选。在返回的子字符串中应包括的字符个数。 说明 如果 length 为 0 或负数,将返回一个空字符串。 如果没有指定该参数,则子字符串将延续到stringObject的最后。
举例: var str = "0123456789";
alert(str.substring(0));------------"0123456789"
alert(str.substring(5));------------"56789"
alert(str.substring(10));-----------""
alert(str.substring(12));-----------""
alert(str.substring(-5));-----------"0123456789"
alert(str.substring(-10));----------"0123456789"
alert(str.substring(-12));----------"0123456789"
alert(str.substring(0,5));----------"01234"
alert(str.substring(0,10));---------"0123456789"
alert(str.substring(0,12));---------"0123456789"
alert(str.substring(2,0));----------"01"
alert(str.substring(2,2));----------""
alert(str.substring(2,5));----------"234"
alert(str.substring(2,12));---------"23456789"
alert(str.substring(2,-2));---------"01"
alert(str.substring(-1,5));---------"01234"
alert(str.substring(-1,-5));--------""
好了,到这里就跟大家分享完成了,如果大家还是不知道是怎么实现的,或者还存在有不理解的地方,都是可以留言咨询。
本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!
在网站编程制作中,对于字符串的切割截取平时所用可能不是特别多,而且分的比较细,所以自备自查。有备无患。由于之前所有均在一个demo测试,下面就来跟大家分享一下成果。
1.函数:split()
功能:使用一个指定的分隔符把一个字符串分割存储到数组
例子: str=”jpg|bmp|gif|ico|png”; arr=str.split(”|”);
//arr是一个包含字符值”jpg”、”bmp”、”gif”、”ico”和”png”的数组
2.函数:join()
功能:使用您选择的分隔符将一个数组合并为一个字符串
例子: var delimitedString=myArray.join(delimiter);
var myList=new Array(”jpg”,”bmp”,”gif”,”ico”,”png”);
var portableList=myList.join(”|”);
//结果是jpg|bmp|gif|ico|png
3.函数:concat()
功能:将两个数组连接在一起;
例子:arr1=[1,2,3,4]
arr2=[5,6,7,8]
alert(arr1.concat(arr2)) //结果为[1,2,3,4,5,6,7,8]
4.函数:charAt()
功能:返回指定位置的字符。字符串中第一个字符的下标是 0。如果参数 index 不在 0 与 string.length 之间,该方法将返回一个空字符串。
例子:var str='a,g,i,d,o,v,w,d,k,p'
alert(str.charAt(2)) //结果为g
5:函数:charCodeAt()
功能:charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
方法 charCodeAt() 与 charAt() 方法执行的操作相似,只不过前者返回的是位于指定位置的字符的编码,而后者返回的是字符子串。
例子:var str='a,g,i,d,o,v,w,d,k,p'
alert(str.charCodeAt(2)) //结果为103。即g的Unicode编码为103
6.函数:slice()
功能:arrayObject.slice(start,end)
start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end:可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
返回一个新的数组,包含从start到end(不包括该元素)的arrayobject中的元素。
例子:var str='ahji3o3s4e6p8a0sdewqdasj'
alert(str.slice(2,5)) //结果ji3
7.函数:substring()
定义和用法 substring 方法用于提取字符串中介于两个指定下标之间的字符。
语法 stringObject.substring(start,stop)
start 必需。一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置。
stop 可选。一个非负的整数,比要提取的子串的最后一个字符在 stringObject 中的位置多 1。
如果省略该参数,那么返回的子串会一直到字符串的结尾。
返回 一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 start 处到 stop-1 处的所有字符,其长度为 stop 减 start。 说明 substring 方法返回的子串包括 start 处的字符,但不包括 end 处的字符。 如果 start 与 end 相等,那么该方法返回的就是一个空串(即长度为 0 的字符串)。 如果 start 比 end 大,那么该方法在提取子串之前会先交换这两个参数。 如果 start 或 end 为负数,那么它将被替换为 0。
例子:var str='ahji3o3s4e6p8a0sdewqdasj'
alert(str.substring(2,6)) //结果为ji3o3
8.函数:substr
定义和用法 substr 方法用于返回一个从指定位置开始的指定长度的子字符串。
语法 stringObject.substr(start [, length ])
参数 start 必需。所需的子字符串的起始位置。字符串中的第一个字符的索引为 0。
length 可选。在返回的子字符串中应包括的字符个数。 说明 如果 length 为 0 或负数,将返回一个空字符串。 如果没有指定该参数,则子字符串将延续到stringObject的最后。
举例: var str = "0123456789";
alert(str.substring(0));------------"0123456789"
alert(str.substring(5));------------"56789"
alert(str.substring(10));-----------""
alert(str.substring(12));-----------""
alert(str.substring(-5));-----------"0123456789"
alert(str.substring(-10));----------"0123456789"
alert(str.substring(-12));----------"0123456789"
alert(str.substring(0,5));----------"01234"
alert(str.substring(0,10));---------"0123456789"
alert(str.substring(0,12));---------"0123456789"
alert(str.substring(2,0));----------"01"
alert(str.substring(2,2));----------""
alert(str.substring(2,5));----------"234"
alert(str.substring(2,12));---------"23456789"
alert(str.substring(2,-2));---------"01"
alert(str.substring(-1,5));---------"01234"
alert(str.substring(-1,-5));--------""
好了,到这里就跟大家分享完成了,如果大家还是不知道是怎么实现的,或者还存在有不理解的地方,都是可以留言咨询。
本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!
收起阅读 »
uni-app自定义返回逻辑教程
自 HBuilderX v1.1.0 起,uni-app 的页面新增 onBackPress(event)
生命周期函数。
onBackPress(event)
返回 event ={from: backbutton | navigateBack}
说明
当用户进行以下操作时,会触发该函数:
- Android 实体返回键 (
from = backbutton
) - 顶部导航栏左边的返回按钮 (
from = backbutton
) - 返回 API,即
uni.navigateBack()
(from = navigateBack
)
注意事项:
- 只有在该函数中返回值为 true 时,才表示不执行默认的返回,自行处理此时的业务逻辑。
- 当不阻止页面返回却直接调用页面路由相关接口(如:uni.switchTab)时,可能会导致页面显示异常,可以通过延迟调用路由相关接口解决。
- 不返回或返回其它值,均会执行默认的返回行为。
- H5 平台,顶部导航栏返回按钮支持
onBackPress()
,浏览器默认返回按键及Android手机实体返回键不支持onBackPress()
- 暂不支持直接在自定义组件中配置该函数,目前只能是在页面中来处理。
场景示例
页面返回
场景说明:
页面中的遮罩处于显示状态时,点击返回不希望直接关闭页面,而是隐藏掉遮罩。遮罩隐藏后,继续点击返回再执行默认的逻辑。
自定义遮罩
通常自定义的遮罩/弹出层,都会做成组件,这样方便复用。
新建 uni-app 项目->components->mask.vue 文件,代码如下:
<template>
<view>
<view class="cpt-mask">
</view>
</view>
</template>
<script>
export default {}
</script>
<style>
.cpt-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
z-index: 99;
}
</style>
引用遮罩组件
在页面中引入 mask 自定义组件后,通过一个状态值来控制其隐藏/显示。
<mask v-if="showMask"></mask>
这里用 v-if,不要用 v-show,自定义组件存在一些问题待优化。
处理返回逻辑
在 onBackPress 中,判定当前遮罩是否处于显示状态。如果显示,则关闭遮罩并返回 true。
onBackPress() {
if(this.showMask) {
this.showMask = false;
return true;
}
},
多级返回
部分业务场景下,返回的逻辑中需要返回多级页面。
由于 uni.navigateBack() 同样会触发 onBackPress 函数。因此在 onBackPress 中直接调用 uni.navigateBack() 并始终返回 true 会引发死循环。
此时,需要根据 onBackPress 的回调对象中的 from 值来做处理,当来源是 'navigateBack' 时,返回 false。
<template>
<view>
</view>
</template>
<script>
export default {
data() {
return {};
},
onBackPress(options) {
if (options.from === 'navigateBack') {
return false;
}
this.back();
return true;
},
methods: {
back() {
uni.navigateBack({
delta: 2
});
}
},
}
</script>
<style>
</style>
应用退出
场景说明:
若在App首页,点击手机物理返回键,此时无返回页面可关闭,uni-app默认会提示“再按一次退出应用”;若想自定义退出信息,如修改为:出现一个拟态窗口提示我们是否退出应用,点击确定退出应用。点击取消,不做操作。
实现方案:
在 onBackPress 中,遮罩不显示的状态下,点击返回键将弹出拟态窗。
onBackPress() {
if(this.showMask) {
this.showMask = false;
return true;
}else{
uni.showModal({
title: '提示',
content: '是否退出uni-app?',
success: function(res) {
if (res.confirm) {
// 退出当前应用,改方法只在App中生效
plus.runtime.quit();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
return true
}
},
实现效果如下图:

运行体验
完整的示例代码,见附件。解压后,拖至 HBuilderX 运行即可。
自 HBuilderX v1.1.0 起,uni-app 的页面新增 onBackPress(event)
生命周期函数。
onBackPress(event)
返回 event ={from: backbutton | navigateBack}
说明
当用户进行以下操作时,会触发该函数:
- Android 实体返回键 (
from = backbutton
) - 顶部导航栏左边的返回按钮 (
from = backbutton
) - 返回 API,即
uni.navigateBack()
(from = navigateBack
)
注意事项:
- 只有在该函数中返回值为 true 时,才表示不执行默认的返回,自行处理此时的业务逻辑。
- 当不阻止页面返回却直接调用页面路由相关接口(如:uni.switchTab)时,可能会导致页面显示异常,可以通过延迟调用路由相关接口解决。
- 不返回或返回其它值,均会执行默认的返回行为。
- H5 平台,顶部导航栏返回按钮支持
onBackPress()
,浏览器默认返回按键及Android手机实体返回键不支持onBackPress()
- 暂不支持直接在自定义组件中配置该函数,目前只能是在页面中来处理。
场景示例
页面返回
场景说明:
页面中的遮罩处于显示状态时,点击返回不希望直接关闭页面,而是隐藏掉遮罩。遮罩隐藏后,继续点击返回再执行默认的逻辑。
自定义遮罩
通常自定义的遮罩/弹出层,都会做成组件,这样方便复用。
新建 uni-app 项目->components->mask.vue 文件,代码如下:
<template>
<view>
<view class="cpt-mask">
</view>
</view>
</template>
<script>
export default {}
</script>
<style>
.cpt-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
opacity: 0.5;
z-index: 99;
}
</style>
引用遮罩组件
在页面中引入 mask 自定义组件后,通过一个状态值来控制其隐藏/显示。
<mask v-if="showMask"></mask>
这里用 v-if,不要用 v-show,自定义组件存在一些问题待优化。
处理返回逻辑
在 onBackPress 中,判定当前遮罩是否处于显示状态。如果显示,则关闭遮罩并返回 true。
onBackPress() {
if(this.showMask) {
this.showMask = false;
return true;
}
},
多级返回
部分业务场景下,返回的逻辑中需要返回多级页面。
由于 uni.navigateBack() 同样会触发 onBackPress 函数。因此在 onBackPress 中直接调用 uni.navigateBack() 并始终返回 true 会引发死循环。
此时,需要根据 onBackPress 的回调对象中的 from 值来做处理,当来源是 'navigateBack' 时,返回 false。
<template>
<view>
</view>
</template>
<script>
export default {
data() {
return {};
},
onBackPress(options) {
if (options.from === 'navigateBack') {
return false;
}
this.back();
return true;
},
methods: {
back() {
uni.navigateBack({
delta: 2
});
}
},
}
</script>
<style>
</style>
应用退出
场景说明:
若在App首页,点击手机物理返回键,此时无返回页面可关闭,uni-app默认会提示“再按一次退出应用”;若想自定义退出信息,如修改为:出现一个拟态窗口提示我们是否退出应用,点击确定退出应用。点击取消,不做操作。
实现方案:
在 onBackPress 中,遮罩不显示的状态下,点击返回键将弹出拟态窗。
onBackPress() {
if(this.showMask) {
this.showMask = false;
return true;
}else{
uni.showModal({
title: '提示',
content: '是否退出uni-app?',
success: function(res) {
if (res.confirm) {
// 退出当前应用,改方法只在App中生效
plus.runtime.quit();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
return true
}
},
实现效果如下图:
运行体验
完整的示例代码,见附件。解压后,拖至 HBuilderX 运行即可。
收起阅读 »
HBuilderX 在server 2008 64x中使用中,突然闪退 代码消失找不回
HBuilderX 在server 2008 64x中使用中,突然闪退 代码消失找不回
当前编辑代码消盟,直接找不回,大家小心使用本软件!
HBuilderX 在server 2008 64x中使用中,突然闪退 代码消失找不回
当前编辑代码消盟,直接找不回,大家小心使用本软件!

vue h5+app蓝牙打印小票
参考网址:
链接蓝牙:https://blog.csdn.net/cxgasd/article/details/78208708
蓝牙打印机指令:https://www.jianshu.com/p/c0b6d1a4823b
1,打印出来的文本是字节流,平常的换行,样式都用不了
2,一行字母有32个字符,一行全部 中文有16个字符 ,1中文=2字母 ,js判断字符串个数
strLen: function(val) {
var len = 0;
for (var i = 0; i < val.length; i++) {
var a = val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
len += 1;
} else {
len += 0.5;
}
}
return len;
}
实现字符串 拼接的方法: 左右对齐是中间填空格,隔行是一行32个空格
-
蓝牙打印机指令 可以实现 文字放大,图案
btOutStream.write(0x1B);
btOutStream.write(0x40);
//或者
// btOutStream.write([0x1B,0x40]);
//打印小票
printComponent:{
//字符个数
strLen:function(val) {
var len = 0;
for (var i = 0; i < val.length; i++) {
var a= val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
len += 1;
}else {
len += 0.5;
}
}
return len;
},
//空格
spacing:function(str){
var blank="";
var row=Math.ceil(this.strLen(str)/16); //行数
var len=(16*row-this.strLen(str))*2;
for(var i=0;i<len;i++){
blank+=' ';
}
console.log((str+blank).length);
return str+blank;
},
//左右对齐
justify:function(str1,str2){
var blank="";
var len=(16-this.strLen(str1)-this.strLen(str2))*2;
for(var i=0;i<len;i++){
blank+=' ';
}
return str1+blank+str2;
},
//分割线
newline:function(){
var line="--------------------------------";
return line;
},
//打印(拣货单)
print3:function(_this){
var str='';
//str+=' —YOULENONG— ';
str+=this.spacing(' ');
str+=this.spacing('订单号:'+_this.order_no);
for(var i=0;i<_this.goodsArr.length;i++){
var v=_this.goodsArr[i];
str+=this.spacing(v.goods_name);
str+=this.justify('销价:'+v.goods_price+'/'+v.unit,'购买量:'+v.goods_num);
str+=this.spacing('货号:'+v.product_no);
//str+=this.justify('折扣:-xxx','折后:xxx');
str+=this.newline();
}
str+=this.spacing(new Date().Format('MM-dd hh:mm:ss'));
str+=this.spacing(' ');
str+=this.spacing(' ');
str+=this.spacing(' ');
_this.bluetoothTool.sendData(str); //把字符串 发给蓝牙,打印
}
}
附件有代码,我删减了,不保证运行成功,得看懂vue
参考网址:
链接蓝牙:https://blog.csdn.net/cxgasd/article/details/78208708
蓝牙打印机指令:https://www.jianshu.com/p/c0b6d1a4823b
1,打印出来的文本是字节流,平常的换行,样式都用不了
2,一行字母有32个字符,一行全部 中文有16个字符 ,1中文=2字母 ,js判断字符串个数
strLen: function(val) {
var len = 0;
for (var i = 0; i < val.length; i++) {
var a = val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
len += 1;
} else {
len += 0.5;
}
}
return len;
}
实现字符串 拼接的方法: 左右对齐是中间填空格,隔行是一行32个空格
-
蓝牙打印机指令 可以实现 文字放大,图案
btOutStream.write(0x1B);
btOutStream.write(0x40);
//或者
// btOutStream.write([0x1B,0x40]);
//打印小票
printComponent:{
//字符个数
strLen:function(val) {
var len = 0;
for (var i = 0; i < val.length; i++) {
var a= val.charAt(i);
if (a.match(/[^\x00-\xff]/ig) != null) {
len += 1;
}else {
len += 0.5;
}
}
return len;
},
//空格
spacing:function(str){
var blank="";
var row=Math.ceil(this.strLen(str)/16); //行数
var len=(16*row-this.strLen(str))*2;
for(var i=0;i<len;i++){
blank+=' ';
}
console.log((str+blank).length);
return str+blank;
},
//左右对齐
justify:function(str1,str2){
var blank="";
var len=(16-this.strLen(str1)-this.strLen(str2))*2;
for(var i=0;i<len;i++){
blank+=' ';
}
return str1+blank+str2;
},
//分割线
newline:function(){
var line="--------------------------------";
return line;
},
//打印(拣货单)
print3:function(_this){
var str='';
//str+=' —YOULENONG— ';
str+=this.spacing(' ');
str+=this.spacing('订单号:'+_this.order_no);
for(var i=0;i<_this.goodsArr.length;i++){
var v=_this.goodsArr[i];
str+=this.spacing(v.goods_name);
str+=this.justify('销价:'+v.goods_price+'/'+v.unit,'购买量:'+v.goods_num);
str+=this.spacing('货号:'+v.product_no);
//str+=this.justify('折扣:-xxx','折后:xxx');
str+=this.newline();
}
str+=this.spacing(new Date().Format('MM-dd hh:mm:ss'));
str+=this.spacing(' ');
str+=this.spacing(' ');
str+=this.spacing(' ');
_this.bluetoothTool.sendData(str); //把字符串 发给蓝牙,打印
}
}
附件有代码,我删减了,不保证运行成功,得看懂vue
收起阅读 »