Hello MUI发布列表到详情最佳实践
Hello MUI在“模板”分类中增加了“列表到详情最佳实践”,先看效果:
从如上gif图中,可看出本示例的主要特点:点击列表瞬间打开详情页,并且详情页已渲染完毕,效果堪比原生App!
本模板设计目标:演示在窗口动画期间完成页面渲染
下面简单介绍一下实现思路,开发者可以套用这个模板,修改服务端地址及对应业务参数,即可实现同样流畅平滑的窗口切换效果。
实现思路:
预加载详情页
在列表页中预加载详情页,列表页中点击某新闻时,通过自定义事件通知详情页加载对应新闻详情,这样可以避免每次打开新闻详情时重新创建webview的资源消耗。
mui.plusReady(function() {
//预加载详情页
webview_detail = mui.preload({
url: 'detail.html',
id: 'vue_demo_detail',
styles: {
"render": "always",//一直渲染
"popGesture": "hide",
"titleNView": titleNView//使用原生渐变导航
}
});
});
复用前页数据
详情页的内容需要通过ajax从服务端动态获取,获取之后再渲染,这里需要耗费一定的时间;如果网络不好,用户就会看到白屏或空页面,体验不好;
实际上,详情页部分内容在列表页已经加载过,可以直接从列表页传递过来(自定义事件耗时<10毫秒),而无需等待网络响应(ajax耗时 > 50毫秒)。因此,在列表页点击事件中,将列表页已加载的、详情页也需要的信息通过自定义事件传递给详情页,详情页将这些数据立即渲染,然后再通过ajax动态获取其余部分的数据。
1、列表页点击事件中传递已加载数据
//触发子窗口变更新闻详情
mui.fire(webview_detail, 'get_detail', {
guid: guid,
title:title,
author:author,
time:time,
cover:cover
});
2、详情页获取前页数据后,立即渲染,再通过ajx请求其余数据
//监听自定义事件,获取新闻详情
document.addEventListener('get_detail', function(event) {
var guid = event.detail.guid;
if(!guid) {
return;
}
//前页传入的数据,直接渲染,无需等待ajax请求详情后
vm.cover = event.detail.cover;
vm.title = event.detail.title;
vm.author = event.detail.author;
vm.time = event.detail.time;
//向服务端请求文章详情内容
mui.ajax('your-server-url' + guid, {
type:'GET',
dataType: 'json', //服务器返回json格式数据
timeout: 15000, //15秒超时
success: function(rsp) {
vm.content = rsp.content;
},
error: function(xhr, type, errorThrown) {
mui.toast('获取文章内容失败');
//TODO 此处可以向服务端告警
}
});
});
详情页返回时重置页面数据
为了避免打开下一个新闻详情时,闪一下上一个新闻详情,模板在详情页返回时,会清空详情页数据;因为本模板使用了vue框架,实际上执行的就是重置vue数据。
实现较为简单,重写mui.back,代码示例如下:
//重写返回逻辑,返回时隐藏详情页webview
mui.back = function() {
plus.webview.currentWebview().hide("auto", 300);
}
//窗口隐藏时,重置页面数据
mui.plusReady(function () {
var self = plus.webview.currentWebview();
self.addEventListener("hide",function (e) {
window.scrollTo(0, 0);//重置滚动条位置
vm.resetData();//重置页面数据
},false);
})
其中,vm.resetData()为清空vue数据的方法。
致谢,感谢 @redonion42@163.com 建议,通过hide事件同时处理back按键、侧滑返回的重置需求。
提高网络响应
核心实现就如上两点,开发者按照这种模板就可以做出同样流畅的App。如果发现响应缓慢,注意检查两点:
- 减少网络传输量,让服务端仅返回前端需要的字段
- 利用缓存等技术优化服务端响应,保证ajax请求可以在100毫秒之内获得响应
关联功能点
按照如上思路实现的“列表到详情最佳实践”,还牵扯到一些关联知识点:
1、集成vue
本示例的列表页、详情页均使用了vue框架实现数据绑定,涉及到vue的列表渲染、数据重置知识点,内容较为简单,源码完全开源,本文不再详述。
2、下拉刷新、上拉加载
列表页集成了下拉刷新、上拉加载,代码示例如下:
mui.init({
pullRefresh: {
container: '#list',
down: {
style: 'circle',
offset: '0px',
auto: true,
callback: pulldownRefresh
},
up: {
contentrefresh: '正在加载...',
callback: pullupRefresh
}
}
});
相关教程参考:
3、透明渐变导航
详情页使用了原生版本的透明渐变导航,参考教程
在点击不同新闻详情页时,需要改变原生导航条上的标题内容,通过重新设置webview的style属性即可,示例如下:
//更改详情页原生导航条信息
titleNView.titleText = title;
webview_detail.setStyle({
"titleNView": titleNView
});
Hello MUI中体验
最新版的Hello MUI已集成了"列表到详情最佳实践",在HBuilder 8.8.0+ 版本中即可体验,体验路径:Hello MUI首页--> 列表到详情最佳实践
Hello MUI在“模板”分类中增加了“列表到详情最佳实践”,先看效果:
从如上gif图中,可看出本示例的主要特点:点击列表瞬间打开详情页,并且详情页已渲染完毕,效果堪比原生App!
本模板设计目标:演示在窗口动画期间完成页面渲染
下面简单介绍一下实现思路,开发者可以套用这个模板,修改服务端地址及对应业务参数,即可实现同样流畅平滑的窗口切换效果。
实现思路:
预加载详情页
在列表页中预加载详情页,列表页中点击某新闻时,通过自定义事件通知详情页加载对应新闻详情,这样可以避免每次打开新闻详情时重新创建webview的资源消耗。
mui.plusReady(function() {
//预加载详情页
webview_detail = mui.preload({
url: 'detail.html',
id: 'vue_demo_detail',
styles: {
"render": "always",//一直渲染
"popGesture": "hide",
"titleNView": titleNView//使用原生渐变导航
}
});
});
复用前页数据
详情页的内容需要通过ajax从服务端动态获取,获取之后再渲染,这里需要耗费一定的时间;如果网络不好,用户就会看到白屏或空页面,体验不好;
实际上,详情页部分内容在列表页已经加载过,可以直接从列表页传递过来(自定义事件耗时<10毫秒),而无需等待网络响应(ajax耗时 > 50毫秒)。因此,在列表页点击事件中,将列表页已加载的、详情页也需要的信息通过自定义事件传递给详情页,详情页将这些数据立即渲染,然后再通过ajax动态获取其余部分的数据。
1、列表页点击事件中传递已加载数据
//触发子窗口变更新闻详情
mui.fire(webview_detail, 'get_detail', {
guid: guid,
title:title,
author:author,
time:time,
cover:cover
});
2、详情页获取前页数据后,立即渲染,再通过ajx请求其余数据
//监听自定义事件,获取新闻详情
document.addEventListener('get_detail', function(event) {
var guid = event.detail.guid;
if(!guid) {
return;
}
//前页传入的数据,直接渲染,无需等待ajax请求详情后
vm.cover = event.detail.cover;
vm.title = event.detail.title;
vm.author = event.detail.author;
vm.time = event.detail.time;
//向服务端请求文章详情内容
mui.ajax('your-server-url' + guid, {
type:'GET',
dataType: 'json', //服务器返回json格式数据
timeout: 15000, //15秒超时
success: function(rsp) {
vm.content = rsp.content;
},
error: function(xhr, type, errorThrown) {
mui.toast('获取文章内容失败');
//TODO 此处可以向服务端告警
}
});
});
详情页返回时重置页面数据
为了避免打开下一个新闻详情时,闪一下上一个新闻详情,模板在详情页返回时,会清空详情页数据;因为本模板使用了vue框架,实际上执行的就是重置vue数据。
实现较为简单,重写mui.back,代码示例如下:
//重写返回逻辑,返回时隐藏详情页webview
mui.back = function() {
plus.webview.currentWebview().hide("auto", 300);
}
//窗口隐藏时,重置页面数据
mui.plusReady(function () {
var self = plus.webview.currentWebview();
self.addEventListener("hide",function (e) {
window.scrollTo(0, 0);//重置滚动条位置
vm.resetData();//重置页面数据
},false);
})
其中,vm.resetData()为清空vue数据的方法。
致谢,感谢 @redonion42@163.com 建议,通过hide事件同时处理back按键、侧滑返回的重置需求。
提高网络响应
核心实现就如上两点,开发者按照这种模板就可以做出同样流畅的App。如果发现响应缓慢,注意检查两点:
- 减少网络传输量,让服务端仅返回前端需要的字段
- 利用缓存等技术优化服务端响应,保证ajax请求可以在100毫秒之内获得响应
关联功能点
按照如上思路实现的“列表到详情最佳实践”,还牵扯到一些关联知识点:
1、集成vue
本示例的列表页、详情页均使用了vue框架实现数据绑定,涉及到vue的列表渲染、数据重置知识点,内容较为简单,源码完全开源,本文不再详述。
2、下拉刷新、上拉加载
列表页集成了下拉刷新、上拉加载,代码示例如下:
mui.init({
pullRefresh: {
container: '#list',
down: {
style: 'circle',
offset: '0px',
auto: true,
callback: pulldownRefresh
},
up: {
contentrefresh: '正在加载...',
callback: pullupRefresh
}
}
});
相关教程参考:
3、透明渐变导航
详情页使用了原生版本的透明渐变导航,参考教程
在点击不同新闻详情页时,需要改变原生导航条上的标题内容,通过重新设置webview的style属性即可,示例如下:
//更改详情页原生导航条信息
titleNView.titleText = title;
webview_detail.setStyle({
"titleNView": titleNView
});
Hello MUI中体验
最新版的Hello MUI已集成了"列表到详情最佳实践",在HBuilder 8.8.0+ 版本中即可体验,体验路径:Hello MUI首页--> 列表到详情最佳实践
收起阅读 »独家系统全套mui,h5+教程,500节课程,文档,资料,20套app源码等
HTML CSS H5 JS Castapp.js,MUI,H5+,PHP mysql,React-Native,Ecmascript6,React.js mui-UI实战 mui,h5+ APP开发实战功能 app开发{仿支付宝,仿微信,仿e袋洗,仿驾考宝典,仿微店,仿教室帮,仿饿了么,仿糗事百科,仿猫眼电影,仿天猫,仿今日头条,东翌同城约,东翌课堂,全套实战开发,让大家快速学习APP开发全体课程只需要499啦 想学习的点击链接咨询 群239503027直播视频课程
HTML CSS H5 JS Castapp.js,MUI,H5+,PHP mysql,React-Native,Ecmascript6,React.js mui-UI实战 mui,h5+ APP开发实战功能 app开发{仿支付宝,仿微信,仿e袋洗,仿驾考宝典,仿微店,仿教室帮,仿饿了么,仿糗事百科,仿猫眼电影,仿天猫,仿今日头条,东翌同城约,东翌课堂,全套实战开发,让大家快速学习APP开发全体课程只需要499啦 想学习的点击链接咨询 群239503027直播视频课程
收起阅读 »关于IMEI设备标记
Android
Android的imei在os层面有api,在plus.device.imei里有封装。
但注意双卡手机有2个imei,会都取出来。
同时注意目前很多Android手机获取imei需要用户授权,当用户不授权时,plus api会自动给出一个随机数,类似于web中的uv的机制。
iOS
iOS没有在os层面提供获取imei的api,plus.device提供了uuid。
Android
Android的imei在os层面有api,在plus.device.imei里有封装。
但注意双卡手机有2个imei,会都取出来。
同时注意目前很多Android手机获取imei需要用户授权,当用户不授权时,plus api会自动给出一个随机数,类似于web中的uv的机制。
iOS
iOS没有在os层面提供获取imei的api,plus.device提供了uuid。
收起阅读 »独家系统全套mui,h5+教程,500节课程,文档,资料,20套app源码等
HTML CSS H5 JS Castapp.js,MUI,H5+,PHP mysql,React-Native,Ecmascript6,React.js mui-UI实战 mui,h5+ APP开发实战功能 app开发{仿支付宝,仿微信,仿e袋洗,仿驾考宝典,仿微店,仿教室帮,仿饿了么,仿糗事百科,仿猫眼电影,仿天猫,仿今日头条,东翌同城约,东翌课堂,全套实战开发,让大家快速学习APP开发全体课程只需要499啦 想学习的点击链接咨询 群239503027上午十点直播课程
HTML CSS H5 JS Castapp.js,MUI,H5+,PHP mysql,React-Native,Ecmascript6,React.js mui-UI实战 mui,h5+ APP开发实战功能 app开发{仿支付宝,仿微信,仿e袋洗,仿驾考宝典,仿微店,仿教室帮,仿饿了么,仿糗事百科,仿猫眼电影,仿天猫,仿今日头条,东翌同城约,东翌课堂,全套实战开发,让大家快速学习APP开发全体课程只需要499啦 想学习的点击链接咨询 群239503027上午十点直播课程
收起阅读 »关于图片分享(IOS与安卓之间的区别)
查阅 **http://www.html5plus.org/doc/zh_cn/share.html#plus.share.ShareMessage**
发现其中
pictures: (Array[ String ] 类型 )分享消息的图片
分享消息中包含的图片路径,仅支持本地路径。 若分享平台仅支持提交一张图片,传入多张图片则仅提交第一张图片。 如果不能同时支持其它内容信息,优先级顺序为:pictures>content。
所提及的是图片路径应该是绝对路径,但经测试,在安卓上是正确的,但在IOS上却是报分享到"微信"失败: -100 - [Share微信:-95]未知错误,http://ask.dcloud.net.cn/article/287查阅文档是图片路径错误的问题,修改无果后便做出如下修改:
if (mui.os.android) { shareMsg.pictures[0] = plus.io.convertLocalFileSystemURL("_www/img1.jpg"); }else if(mui.os.ios){ shareMsg.pictures[0] = "_www/img1.jpg"; }运行测试成功。
在这里有个疑问,如果事实真是这样的,文档是否写错的,还是我这里出现什么问题?
不过有遇到这类问题的朋友,也可以照我以上写法。
查阅 **http://www.html5plus.org/doc/zh_cn/share.html#plus.share.ShareMessage**
发现其中
收起阅读 »pictures: (Array[ String ] 类型 )分享消息的图片
分享消息中包含的图片路径,仅支持本地路径。 若分享平台仅支持提交一张图片,传入多张图片则仅提交第一张图片。 如果不能同时支持其它内容信息,优先级顺序为:pictures>content。
所提及的是图片路径应该是绝对路径,但经测试,在安卓上是正确的,但在IOS上却是报分享到"微信"失败: -100 - [Share微信:-95]未知错误,http://ask.dcloud.net.cn/article/287查阅文档是图片路径错误的问题,修改无果后便做出如下修改:
if (mui.os.android) { shareMsg.pictures[0] = plus.io.convertLocalFileSystemURL("_www/img1.jpg"); }else if(mui.os.ios){ shareMsg.pictures[0] = "_www/img1.jpg"; }运行测试成功。
在这里有个疑问,如果事实真是这样的,文档是否写错的,还是我这里出现什么问题?
不过有遇到这类问题的朋友,也可以照我以上写法。
ios持续定位/后台定位问题
我分享一下我解决IOS和Android定位后台执行定时上传方法。
文章最下面有zip源码下载文件
文章最下面有zip源码下载文件
文章最下面有zip源码下载文件
图1是声明定位的对象 图2是开启 location.js文件中全部封装好了你自己需要的方法 对外只需要暴露的checkLocation closeLocation 2个方法
定位对象必须要是唯一的 如果不唯一就会开启多个定位方法 影响使用
android的如果全杀死是没办法,在后台的情况是没问题的.
我的做法是用watchPosition将获取的到的坐标放在一个数组中,然后调用locationHandle方法每隔多少时间上次到服务器。
这个不会出现上传一段时间之后关掉的情况。
1.在这之前你需要在manifest.json文件中配置启用后台模块"UIBackgroundModes": ["location"]
2.如果定位失败会返回一个5e-324可能是你手机的定位权限没有开启。
var Location = function () {
this.reportLocation = null;
this.watchLocation = null;
this.locationPool = [];
}
/**
* 判断是否开启定位
* @param {Object} isTask 1是开启循环上传定位0是10分钟上传一次本地定位
*/
Location.prototype.checkLocation = function (isTask) {
var _this = this;
_this.openLocation({
onSuccess: function () {
//开启定位成功首页回调方法
var sell_main = plus.webview.getWebviewById('sell_main');
mui.fire(sell_main, 'locationSuccess');
},
onFailed: function () {
//开启定位失败首页回调方法
var sell_main = plus.webview.getWebviewById('sell_main');
mui.fire(sell_main, 'locationFailure');
}
});
}
/**
* 开启定位
* @param {Object} options
*/
Location.prototype.openLocation = function (options) {
options = options || {};
var _this = this;
var isTask = this.isTask;
var driverForOrderObject = null;
var driverForTaskObject = null;
var userInfo = DbUtils.getStorage('userInfo', 1);
var locationParams = {
enableHighAccuracy: true,
geocode: false,
coordsType: "bd09ll",
provider: 'baidu'
};
}
/**
* 默认第一次开启定位的是否先获取 之后用来过滤偏差很大的点
* @param {Object} options
*/
Location.prototype.locationReady = function (options) {
options = options || {};
var isTask = this.isTask;
var _this = this;
var locationParams = {
enableHighAccuracy: true,
geocode: false,
maximumAge: ApiConfig.UPLOADLOCATIONWORKTIME,
coordsType: "bd09ll",
provider: 'baidu'
};
_this.getCurrentPosition()
}
/**
* 非工作状态定位,十五分钟上传一次定位
* @param options
*/
Location.prototype.accurateLocation = function (options) {
options = options || {};
var _this = this;
plus.geolocation.getCurrentPosition(function (position) {
_this.locationPool.push(position);
ApiConfig.staticIsDebug('getCurrentPosition', JSON.stringify(position));
_this.reportLocationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}, function () {
options.onFailed && options.onFailed();
}, options.locationParams);
}
/**
* 只要定位改变就会获取并过滤错误的点和偏差很多的点
*坐标为 -5e32是定位权限没开启的情况
* @param options
*/
Location.prototype.getCurrentPosition = function (options) {
options = options || {};
var _this = this;
var phpTimeInt = utilsJs.phpTimeInt();
var isWork = options.isWork;
var locationParams = options.locationParams;
//初始化Location参数
if (_this.reportLocation) {
window.clearInterval(_this.reportLocation);
_this.reportLocation = null;
}
if (_this.watchLocation) {
plus.geolocation.clearWatch(_this.watchLocation);
_this.reportLocation = null;
}
//是否是工作状态 工作状态用watchPosition 非工作状态用getCurrentPosition
if (isWork) {
_this.watchLocation = plus.geolocation.watchPosition(function (position) {
//console.log(JSON.stringify(position));
var difference = (position.timestamp / 1000) - phpTimeInt;
var coords = position.coords;
if (coords.latitude > 0.00000001 && coords.longitude > 0.00000001 && difference > 1) {
phpTimeInt = (position.timestamp / 1000);
_this.locationPool.push(position);
_this.locationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}
},
function () {
options.onFailed && options.onFailed();
}, locationParams);
} else {
_this.reportLocation = window.setInterval(function () {
_this.accurateLocation(options);
}, ApiConfig.UPLOADLOCATIONTIME);
}
}
//开启定时器
Location.prototype.locationHandle = function (options) {
options = options || {};
var _this = this;
if (!_this.reportLocation) {
_this.reportLocation = window.setInterval(function () {
//plus.push.createMessage('locationPool:' + _this.locationPool.length, '', '');
_this.reportLocationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}, ApiConfig.UPLOADLOCATIONWORKTIME);
}
}
/**
* 关闭定位
*
*/
Location.prototype.closeLocation = function () {
var _this = this;
var isTask = this.isTask;
if (_this.reportLocation) {
window.clearInterval(_this.reportLocation);
_this.reportLocation = null;
}
if (_this.watchLocation) {
plus.geolocation.clearWatch(_this.watchLocation);
_this.watchLocation = null;
}
this.locationPool = [];
if (isTask) {
DbUtils.removeItem('driverStatusForTask');
} else {
DbUtils.removeItem('driverStatusObject');
}
}
/**
* 上传定位接口
* @param options
*/
Location.prototype.reportLocationHandle = function (options) {
} 我分享一下我解决IOS和Android定位后台执行定时上传方法。
文章最下面有zip源码下载文件
文章最下面有zip源码下载文件
文章最下面有zip源码下载文件
图1是声明定位的对象 图2是开启 location.js文件中全部封装好了你自己需要的方法 对外只需要暴露的checkLocation closeLocation 2个方法
定位对象必须要是唯一的 如果不唯一就会开启多个定位方法 影响使用
android的如果全杀死是没办法,在后台的情况是没问题的.
我的做法是用watchPosition将获取的到的坐标放在一个数组中,然后调用locationHandle方法每隔多少时间上次到服务器。
这个不会出现上传一段时间之后关掉的情况。
1.在这之前你需要在manifest.json文件中配置启用后台模块"UIBackgroundModes": ["location"]
2.如果定位失败会返回一个5e-324可能是你手机的定位权限没有开启。
var Location = function () {
this.reportLocation = null;
this.watchLocation = null;
this.locationPool = [];
}
/**
* 判断是否开启定位
* @param {Object} isTask 1是开启循环上传定位0是10分钟上传一次本地定位
*/
Location.prototype.checkLocation = function (isTask) {
var _this = this;
_this.openLocation({
onSuccess: function () {
//开启定位成功首页回调方法
var sell_main = plus.webview.getWebviewById('sell_main');
mui.fire(sell_main, 'locationSuccess');
},
onFailed: function () {
//开启定位失败首页回调方法
var sell_main = plus.webview.getWebviewById('sell_main');
mui.fire(sell_main, 'locationFailure');
}
});
}
/**
* 开启定位
* @param {Object} options
*/
Location.prototype.openLocation = function (options) {
options = options || {};
var _this = this;
var isTask = this.isTask;
var driverForOrderObject = null;
var driverForTaskObject = null;
var userInfo = DbUtils.getStorage('userInfo', 1);
var locationParams = {
enableHighAccuracy: true,
geocode: false,
coordsType: "bd09ll",
provider: 'baidu'
};
}
/**
* 默认第一次开启定位的是否先获取 之后用来过滤偏差很大的点
* @param {Object} options
*/
Location.prototype.locationReady = function (options) {
options = options || {};
var isTask = this.isTask;
var _this = this;
var locationParams = {
enableHighAccuracy: true,
geocode: false,
maximumAge: ApiConfig.UPLOADLOCATIONWORKTIME,
coordsType: "bd09ll",
provider: 'baidu'
};
_this.getCurrentPosition()
}
/**
* 非工作状态定位,十五分钟上传一次定位
* @param options
*/
Location.prototype.accurateLocation = function (options) {
options = options || {};
var _this = this;
plus.geolocation.getCurrentPosition(function (position) {
_this.locationPool.push(position);
ApiConfig.staticIsDebug('getCurrentPosition', JSON.stringify(position));
_this.reportLocationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}, function () {
options.onFailed && options.onFailed();
}, options.locationParams);
}
/**
* 只要定位改变就会获取并过滤错误的点和偏差很多的点
*坐标为 -5e32是定位权限没开启的情况
* @param options
*/
Location.prototype.getCurrentPosition = function (options) {
options = options || {};
var _this = this;
var phpTimeInt = utilsJs.phpTimeInt();
var isWork = options.isWork;
var locationParams = options.locationParams;
//初始化Location参数
if (_this.reportLocation) {
window.clearInterval(_this.reportLocation);
_this.reportLocation = null;
}
if (_this.watchLocation) {
plus.geolocation.clearWatch(_this.watchLocation);
_this.reportLocation = null;
}
//是否是工作状态 工作状态用watchPosition 非工作状态用getCurrentPosition
if (isWork) {
_this.watchLocation = plus.geolocation.watchPosition(function (position) {
//console.log(JSON.stringify(position));
var difference = (position.timestamp / 1000) - phpTimeInt;
var coords = position.coords;
if (coords.latitude > 0.00000001 && coords.longitude > 0.00000001 && difference > 1) {
phpTimeInt = (position.timestamp / 1000);
_this.locationPool.push(position);
_this.locationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}
},
function () {
options.onFailed && options.onFailed();
}, locationParams);
} else {
_this.reportLocation = window.setInterval(function () {
_this.accurateLocation(options);
}, ApiConfig.UPLOADLOCATIONTIME);
}
}
//开启定时器
Location.prototype.locationHandle = function (options) {
options = options || {};
var _this = this;
if (!_this.reportLocation) {
_this.reportLocation = window.setInterval(function () {
//plus.push.createMessage('locationPool:' + _this.locationPool.length, '', '');
_this.reportLocationHandle({
onSuccess: function (success) {
options.onSuccess && options.onSuccess(success);
},
onFailed: function (failure) {
options.onFailed && options.onFailed(failure);
}
});
}, ApiConfig.UPLOADLOCATIONWORKTIME);
}
}
/**
* 关闭定位
*
*/
Location.prototype.closeLocation = function () {
var _this = this;
var isTask = this.isTask;
if (_this.reportLocation) {
window.clearInterval(_this.reportLocation);
_this.reportLocation = null;
}
if (_this.watchLocation) {
plus.geolocation.clearWatch(_this.watchLocation);
_this.watchLocation = null;
}
this.locationPool = [];
if (isTask) {
DbUtils.removeItem('driverStatusForTask');
} else {
DbUtils.removeItem('driverStatusObject');
}
}
/**
* 上传定位接口
* @param options
*/
Location.prototype.reportLocationHandle = function (options) {
} 收起阅读 »
承接App开发,Vue + Dcloud 目前架构最成熟的跨平台解决方案。
默客 (http://www.mokekeji.com) 原横行科技,专业跨平台App开发。
我们从大约四年前开始混合式App(hybrid app) 的相关开发,从早期的 cordova (原phonegap) 到后来的国内的Dcloud ,ApiCloud ,再到现在的 React Native 以及 Weex,我们切实的看到了混合式App从一开始的饱受诟病到后来的遍地流行,甚至现在我们几乎可以断言混合式App将会成为主流App开发方式,这里不仅是一篇广告,同时会说明我们最终选择Vue + Dcloud的原因。
cordova ,Dcloud , Apicloud 三者都是基于webview 进行封装的,具体的框架对比有很多文章说明,比如这里比较流行的一篇文章http://blog.csdn.net/guzhenping/article/details/50496883
但是所谓文章一旦开始分析优缺点,往往都是各有优劣,其实只有真正开发过,使用过,吃过亏才知道哪个是不能用的。
Apicloud 是不能用的。
必须承认apicloud的营销和用户后台做得都不错,也正是因为这些表面功夫,让我们以花费了接近半年时间,并重构了一个项目的成本,得出了这个结论。
apicloud的开发环境和运行环境有很大不同,这给开发带来了巨大的阻碍,debug也非常艰难。
apicloud的模块数量不少,但质量十分低下,即使最基础的ajax模块都有一堆问题。
apicloud许多模块都有原生的UI,这部分UI质量的定制和使用很难达到商业水准。
总而言之,apicloud并不适合开发人员使用,也不适合商业产品的开发。
开发上来说,cordova 与 Dcloud 各有千秋。
cordova 有成熟的社区,海量的扩展插件,以及许多的成熟解决方案,Dcloud有更好的性能,更好的开发工具,更高的投入产出比。
但我们选择 Dcloud,与我们没有选择React Native的原因一样,一个成熟的商业公司在选择技术框架时,更低的开发门槛实在过于重要了,目前国内的平均前端水准仍然偏低,看懂cordova的开发文档就已经很困难了,插件市场也很难用上。
我们将Dcloud的html5 Plus api 以及 微信js sdk都进行了封装,有一定基础的开发人员可以在很短的时间内掌握,加上Dcloud对于常规需求都有比较接地气的解决方案,开发体验就要好的多。
Mvvm框架是大型应用的必选项
Mvvm框架代表:Vue,react
目前大多数人仍是使用原始的Html页面进行应用开发,包括Dcloud的展示案例也是如此。
这种开发方式在开发大型应用时越来越捉襟见肘,比如如何跨页面管理全局状态就是个不小的问题。
原始的静态页面开发虽然降低了开发成本,但其实大幅增加了维护成本,当前的app对与快速迭代有越来越高的要求,静态页面开发动辄上百个页面,改一个UI颜色,都可能需要半天的时间。
Mvvm框架可以大幅提高代码质量,所有ui可以封装为组件,数据驱动视图,对于复杂的交互来说,结构也更为清晰。
Weex和React Native终成主流
与Dcloud这类框架不同,这两个框架在原生平台上运行时,会将页面编译为原生控件,可以说,这从根本上解决了混合式app的性能问题,我们目前在重点关注Weex,这个框架目前仍未达到商业使用的要求,我们预计在明年我司内部会逐渐用其替代Dcloud作为主开发框架。React Native的问题仍然在开发门槛上,我们只会在少数项目上使用。
我们致力于开发高质量的跨平台应用,业务联系请参考官网。
http://www.mokekeji.com
默客 (http://www.mokekeji.com) 原横行科技,专业跨平台App开发。
我们从大约四年前开始混合式App(hybrid app) 的相关开发,从早期的 cordova (原phonegap) 到后来的国内的Dcloud ,ApiCloud ,再到现在的 React Native 以及 Weex,我们切实的看到了混合式App从一开始的饱受诟病到后来的遍地流行,甚至现在我们几乎可以断言混合式App将会成为主流App开发方式,这里不仅是一篇广告,同时会说明我们最终选择Vue + Dcloud的原因。
cordova ,Dcloud , Apicloud 三者都是基于webview 进行封装的,具体的框架对比有很多文章说明,比如这里比较流行的一篇文章http://blog.csdn.net/guzhenping/article/details/50496883
但是所谓文章一旦开始分析优缺点,往往都是各有优劣,其实只有真正开发过,使用过,吃过亏才知道哪个是不能用的。
Apicloud 是不能用的。
必须承认apicloud的营销和用户后台做得都不错,也正是因为这些表面功夫,让我们以花费了接近半年时间,并重构了一个项目的成本,得出了这个结论。
apicloud的开发环境和运行环境有很大不同,这给开发带来了巨大的阻碍,debug也非常艰难。
apicloud的模块数量不少,但质量十分低下,即使最基础的ajax模块都有一堆问题。
apicloud许多模块都有原生的UI,这部分UI质量的定制和使用很难达到商业水准。
总而言之,apicloud并不适合开发人员使用,也不适合商业产品的开发。
开发上来说,cordova 与 Dcloud 各有千秋。
cordova 有成熟的社区,海量的扩展插件,以及许多的成熟解决方案,Dcloud有更好的性能,更好的开发工具,更高的投入产出比。
但我们选择 Dcloud,与我们没有选择React Native的原因一样,一个成熟的商业公司在选择技术框架时,更低的开发门槛实在过于重要了,目前国内的平均前端水准仍然偏低,看懂cordova的开发文档就已经很困难了,插件市场也很难用上。
我们将Dcloud的html5 Plus api 以及 微信js sdk都进行了封装,有一定基础的开发人员可以在很短的时间内掌握,加上Dcloud对于常规需求都有比较接地气的解决方案,开发体验就要好的多。
Mvvm框架是大型应用的必选项
Mvvm框架代表:Vue,react
目前大多数人仍是使用原始的Html页面进行应用开发,包括Dcloud的展示案例也是如此。
这种开发方式在开发大型应用时越来越捉襟见肘,比如如何跨页面管理全局状态就是个不小的问题。
原始的静态页面开发虽然降低了开发成本,但其实大幅增加了维护成本,当前的app对与快速迭代有越来越高的要求,静态页面开发动辄上百个页面,改一个UI颜色,都可能需要半天的时间。
Mvvm框架可以大幅提高代码质量,所有ui可以封装为组件,数据驱动视图,对于复杂的交互来说,结构也更为清晰。
Weex和React Native终成主流
与Dcloud这类框架不同,这两个框架在原生平台上运行时,会将页面编译为原生控件,可以说,这从根本上解决了混合式app的性能问题,我们目前在重点关注Weex,这个框架目前仍未达到商业使用的要求,我们预计在明年我司内部会逐渐用其替代Dcloud作为主开发框架。React Native的问题仍然在开发门槛上,我们只会在少数项目上使用。
我们致力于开发高质量的跨平台应用,业务联系请参考官网。
http://www.mokekeji.com
关于Appstore版Hello H5+支付示例只有iap的说明
Hello H5+的支付示例是捐赠,按照Appstore的规定属于非实物交易,必须且只能使用Apple的应用内支付iap,并且必须给Apple分成30%。
应Apple要求,新版Hello H5+的iOS版支付示例去掉了微信支付和支付宝支付。但相关api仍然是可以使用的,只能你是实物交易,就可以使用微信、支付宝。当然如果你不打算上Appstore,那想怎么样都行。
如果开发者在Appstore中发行,使用实物交易,比如电商、外卖、电影票。。。不受此影响。如果是非实物交易,比如销售App、游戏道具、打赏捐赠、电子书、音视频会员、知识付费,都必须使用iap。
如果开发者在iOS流应用中发行,没有此限制。即使是非实物交易,也可以使用支付宝支付,对于微信支付,可以使用微信H5支付。
Hello H5+的支付示例是捐赠,按照Appstore的规定属于非实物交易,必须且只能使用Apple的应用内支付iap,并且必须给Apple分成30%。
应Apple要求,新版Hello H5+的iOS版支付示例去掉了微信支付和支付宝支付。但相关api仍然是可以使用的,只能你是实物交易,就可以使用微信、支付宝。当然如果你不打算上Appstore,那想怎么样都行。
如果开发者在Appstore中发行,使用实物交易,比如电商、外卖、电影票。。。不受此影响。如果是非实物交易,比如销售App、游戏道具、打赏捐赠、电子书、音视频会员、知识付费,都必须使用iap。
如果开发者在iOS流应用中发行,没有此限制。即使是非实物交易,也可以使用支付宝支付,对于微信支付,可以使用微信H5支付。
收起阅读 »在开发websocket时 遇到的问题整理
先看了几篇文章,开发大概和web端相同,但是部分机型不兼容(Android4.4以下)。
[其它机型(ios和Android4.4以上)都是直接和web端相同使用]
1. http://ask.dcloud.net.cn/article/1103
试了一下,,貌似不行 0.0,估计使用姿势错误,而且该方面知识不足,于是改用其它方法
2. http://ask.dcloud.net.cn/question/60
把评论里Chuck和Sychel两位的代码合一起 使用,,如下代码块。
连接是成功了,,但是不知道如果监听使用 如 onopen、onmessage、onerror、onclose,,
搞了几个钟,时间不等人,,,下次再研究(这个估计是能实现,,知识不够0.0);
3. http://ask.dcloud.net.cn/question/1114
后端不是使用node.js,并且 貌似会发送polling请求;
4. https://github.com/anismiles/websocket-android-phonegap
尝试使用websocket-android-phonegap
mui.plusReady(function () {
testSocket()
})
function testSocket(){
if (plus.os.name == "Android") {
var Socket = plus.android.importClass("java.net.Socket");
var PrintWriter = plus.android.importClass("java.io.PrintWriter");
var BufferedWriter = plus.android.importClass("java.io.BufferedWriter");
var OutputStreamWriter = plus.android.importClass("java.io.OutputStreamWriter");
var BufferedReader = plus.android.importClass("java.io.BufferedReader");
var InputStreamReader = plus.android.importClass("java.io.InputStreamReader");
//测试改良
var StrictMode = plus.android.importClass("android.os.StrictMode");
var Build = plus.android.importClass("android.os.Build");
if (Build.VERSION.SDK_INT > 9) {
var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
var socket = new Socket("10.0.2.2", 8282);
var outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
var bufferWriter = new BufferedWriter(outputStreamWriter);
var out = new PrintWriter(bufferWriter, true);
out.println("GET / HTTP/1.1\r\n\
Host: zhang.qzone.com:8282\r\n\
Connection: Upgrade\r\n\
Pragma: no-cache\r\n\
Cache-Control: no-cache\r\n\
Upgrade: websocket\r\n\
Origin: http://zhang.qzone.com\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: WvKJ6q11EWhzDwiIVBa31w==\r\n\
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n");
var inputStreamReader = new InputStreamReader(socket.getInputStream());
var br = new BufferedReader(inputStreamReader);
var msg = br.readLine();
//while(true)
{
if(msg != null)
{
console.log(msg);
}
//msg = br.readLine();
}
}
//console.log(mac);
alert("Done");
} 先看了几篇文章,开发大概和web端相同,但是部分机型不兼容(Android4.4以下)。
[其它机型(ios和Android4.4以上)都是直接和web端相同使用]
1. http://ask.dcloud.net.cn/article/1103
试了一下,,貌似不行 0.0,估计使用姿势错误,而且该方面知识不足,于是改用其它方法
2. http://ask.dcloud.net.cn/question/60
把评论里Chuck和Sychel两位的代码合一起 使用,,如下代码块。
连接是成功了,,但是不知道如果监听使用 如 onopen、onmessage、onerror、onclose,,
搞了几个钟,时间不等人,,,下次再研究(这个估计是能实现,,知识不够0.0);
3. http://ask.dcloud.net.cn/question/1114
后端不是使用node.js,并且 貌似会发送polling请求;
4. https://github.com/anismiles/websocket-android-phonegap
尝试使用websocket-android-phonegap
mui.plusReady(function () {
testSocket()
})
function testSocket(){
if (plus.os.name == "Android") {
var Socket = plus.android.importClass("java.net.Socket");
var PrintWriter = plus.android.importClass("java.io.PrintWriter");
var BufferedWriter = plus.android.importClass("java.io.BufferedWriter");
var OutputStreamWriter = plus.android.importClass("java.io.OutputStreamWriter");
var BufferedReader = plus.android.importClass("java.io.BufferedReader");
var InputStreamReader = plus.android.importClass("java.io.InputStreamReader");
//测试改良
var StrictMode = plus.android.importClass("android.os.StrictMode");
var Build = plus.android.importClass("android.os.Build");
if (Build.VERSION.SDK_INT > 9) {
var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
var socket = new Socket("10.0.2.2", 8282);
var outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
var bufferWriter = new BufferedWriter(outputStreamWriter);
var out = new PrintWriter(bufferWriter, true);
out.println("GET / HTTP/1.1\r\n\
Host: zhang.qzone.com:8282\r\n\
Connection: Upgrade\r\n\
Pragma: no-cache\r\n\
Cache-Control: no-cache\r\n\
Upgrade: websocket\r\n\
Origin: http://zhang.qzone.com\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: WvKJ6q11EWhzDwiIVBa31w==\r\n\
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n");
var inputStreamReader = new InputStreamReader(socket.getInputStream());
var br = new BufferedReader(inputStreamReader);
var msg = br.readLine();
//while(true)
{
if(msg != null)
{
console.log(msg);
}
//msg = br.readLine();
}
}
//console.log(mac);
alert("Done");
} 收起阅读 »
2017-06-05 IOS开发两个CSS问题,导致样式失效【box-shadow position:fixed】
今天开发的时候遇到的。
有时候我们需要高亮某个区域,很多人用两层div去做,而我比较喜欢直接的box-shadow,半径超大。。。
问题A:box-shadow 被遮挡,显示不全
出现原因:不告诉你
解决办法:改为 -webkit-box-shadow 同时z-index设计比较大的数字
问题B:box-shadow 失效
出现原因:box-shadow中第4个参数值临界值为 1008
解决办法:都说了临界值为1008,你咋不改小点啊。
格式:(加粗区域为所说的临界值对应区域)
box-shadow 0px 0px 0px **1008**px
问题C:父子fixed,父div位置正常,子div不被渲染。
出现原因:也不告诉你
解决方法:见下文
例子:
<div style="position:fixed;top:50px">
what the f**k(自带敏感词屏蔽)
<div style="position:fixed;top:0px">hello</div>
</div>
此时hello并不会显示,其他平台显示正常。但是如果hello具有点击事件,此时点击顶部依然能够触发事件。
这么奇葩的我还是第一次遇到,可能有人会说这么奇葩的代码你能写出来我也是第一次遇到。
每个人总会偶尔写错一些代码,如上代码其实正常来说是:
<div style="position:fixed;top:0px">hello</div>
<div style="position:fixed;top:50px">
what the f**k(自带敏感词屏蔽)
</div>
因此出现这个问题的你们,应该会处理了吧?
今天开发的时候遇到的。
有时候我们需要高亮某个区域,很多人用两层div去做,而我比较喜欢直接的box-shadow,半径超大。。。
问题A:box-shadow 被遮挡,显示不全
出现原因:不告诉你
解决办法:改为 -webkit-box-shadow 同时z-index设计比较大的数字
问题B:box-shadow 失效
出现原因:box-shadow中第4个参数值临界值为 1008
解决办法:都说了临界值为1008,你咋不改小点啊。
格式:(加粗区域为所说的临界值对应区域)
box-shadow 0px 0px 0px **1008**px
问题C:父子fixed,父div位置正常,子div不被渲染。
出现原因:也不告诉你
解决方法:见下文
例子:
<div style="position:fixed;top:50px">
what the f**k(自带敏感词屏蔽)
<div style="position:fixed;top:0px">hello</div>
</div>
此时hello并不会显示,其他平台显示正常。但是如果hello具有点击事件,此时点击顶部依然能够触发事件。
这么奇葩的我还是第一次遇到,可能有人会说这么奇葩的代码你能写出来我也是第一次遇到。
每个人总会偶尔写错一些代码,如上代码其实正常来说是:
<div style="position:fixed;top:0px">hello</div>
<div style="position:fixed;top:50px">
what the f**k(自带敏感词屏蔽)
</div>
因此出现这个问题的你们,应该会处理了吧?
收起阅读 »mui框架不能用<script />,必须要成对<script></script>
<script src="js/mui.min.js"></script>
如果写成<script src="js/mui.min.js" />会把后面的所有内容认为是js的内容,导致很多奇怪问题,还没什么提示
但是link是可以用<link href="css/mui.min.css" rel="stylesheet" />来结束的,所以具有迷惑性
算是一个不大不小的坑吧,大家注意了
<script src="js/mui.min.js"></script>
如果写成<script src="js/mui.min.js" />会把后面的所有内容认为是js的内容,导致很多奇怪问题,还没什么提示
但是link是可以用<link href="css/mui.min.css" rel="stylesheet" />来结束的,所以具有迷惑性
算是一个不大不小的坑吧,大家注意了
收起阅读 »




