一.ios与安卓样式的兼容问题
1.ios对输入框input无法输入编辑
解决方案: input加上type属性
2.ios对于fixed布局,在输入法弹出来后无法固定
解决方案: 对头部和内容都使用absolute布局,设置内容滚动(overflow-y : auto)
//ios出现软键盘时压缩页面
selfWv.setStyle({
softinputMode:"adjustResize"
})
当输入法弹出时,页面压缩,内容压缩产生滚动,此时是内容滚动非整个页面滚动,则头部固定
3.底部使用fixed布局,在安卓和ios都会被输入法顶起
解决方案: 底部不使用field布局,通过计算页面高度,动态设置padding-top
4.输入法与选择弹出框冲突,即原本该隐藏的弹出框会随输入法显示在页面
解决方案: 改写弹出框源码,在隐藏时判断如果是ios系统,则销毁弹出框
hide: function() {
...
// 添加 By YH
self.hided = true;
//如果是ios,则释放资源,防止与软键盘冲突
if(mui.os.ios) {
self.dispose();
}
},
dispose: function() {
var self = this;
//如果是隐藏过的,就不必再隐藏,防止hide和dispose相互调用死循环
if(!self.hided) {
self.hide();
}
...
},
5.ios通过系统提供的方法不能成功自动打开输入法
解决方案: 通过以下方法打开输入法
plus.key.showSoftKeybord(); //安卓有效,ios无效
tool.openKeyboard = function() { //安卓ios均有效
if (mui.os.android) {
var main = plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var InputMethodManager = plus.android.importClass("android.view.inputmethod.InputMethodManager");
var imm = main.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);
} else {
var nativeWebview = plus.webview.currentWebview().nativeInstanceObject();
nativeWebview.plusCallMethod({
"setKeyboardDisplayRequiresUserAction": false
});
}
};
6.ios上传相册中图片不成功
解决方案: 调用相机返回本地相对路径,调用相册返回平台绝对路径,安卓中两种路径都可上传,ios只能上传本地相对路径,故需转换为本地相对路径
path = plus.io.convertAbsoluteFileSystem(path);
7.iPhoneX通过系统提供的方法获取状态栏高度错误,且存在底部安全区
解决方案: 列举这类特殊设备的状态栏和底部栏的高度,获取高度时判断当前手机型号是否属于此类特殊设备
var device = {
iPhoneX : [44,34]
}
二.开发中的技巧运用
1.页面自适应:容器尺寸间距字体大小等随屏幕大小自动适应
解决方案: 设定html元素的fontSize,所有单位都采用rem。
原本css有提供vw和vh单位,1vw = 1%屏幕宽度,可以不需要js。可惜某些浏览器不兼容。
//1rem = 1/25屏幕宽度
var html = document.documentElement;
html.style.fontSize = window.screen.width / 25 + "px";
2.沉浸式状态栏设置
解决方案: 原有的头部容器需加上状态栏高度,状态栏高度各手机又不尽相同,只能在js中获取并设置
(1)先在app首页获取状态栏高度并存入缓存
//获取手机型号
var model = plus.device.model;
var statusbar = localStorage.getItem(lsKey.statusbar);
if(statusbar == null) {
statusbar = 0;
//如无设置,则判断是否沉浸式,并获取高度
if(plus.navigator.isImmersedStatusbar()) {
//如果是特殊设备,则直接设定,否则通过系统方法获取
if(device[model]) {
statusbar = device[model][0];
} else {
statusbar = plus.navigator.getStatusbarHeight();
}
}
//存入缓存,使得每个页面无须通过plus对象获取
localStorage.setItem(lsKey.statusbar , statusbar);
}
(2)在每个页面(除子页面)中,都执行如下代码,即需放入公共的js中。只要在页面中都使用对应样式即可
$(function(){
//获取浸入式状态栏高度
var barHeight = localStorage.getItem(lsKey.statusbar);
if(barHeight!=null && barHeight!=0) {
barHeight = parseInt(barHeight);
//获取导航栏元素
var header = $(".app-header");
if(header.length > 0) {
//如果存在,则增加导航栏的高度和顶部偏移量
var hh = header.height();
header.height(hh+barHeight);
header.css("padding-top" , barHeight + "px");
}
//获取内容区元素
var content = $(".app-content");
if(content.length > 0) {
//如果存在,则增加内容区的顶部偏移量
var cp = content.css("paddingTop");
cp = parseInt(cp.replace("px",""));
content.css("padding-top" , cp + barHeight + "px");
}
//获取内容区元素
var content2 = $(".app-content2");
if(content2.length > 0) {
//如果存在,则增加内容区的顶部偏移量
var cp = content2.css("top");
cp = parseInt(cp.replace("px",""));
content2.css("top" , cp + barHeight + "px");
}
}
})
3.系统配置相关变量
/*config保存系统配置参数
*/
const config = {
apiUrl : "http://10.1.32.112:8023/",//服务器地址
pagesize : 15,//默认分页的条数
debug : true //调试模式,用于判断是否打印错误信息
};
/* lsKey统一保存localStorage需要使用到的key值,
* 使用getItem,setItem均使用此常数,不直接使用字符串,便于维护
*/
const lsKey = {
bottomHigh: "bottomHigh", //底部导航栏的高度
language : "language", //当前语言
statusbar : "statusbar", //沉浸式状态栏的高度,非浸入式则为0
bottombar : "bottombar", //底部栏的高度,部分手机才有(iphoneX),如无则为0
user : "user", //当前登录的用户
role : "role", //用户角色 : 1-园长,2-教师,3-家长
};
二.工具方法
1.通过JTemplate渲染页面
/* @target 通过jtemplate加载数据
* @param id : 被加载容器的id
* @param data : 加载的数据
*/
tool.loadData = function(id,data) {
var container = $("#"+id);
var template = container.find('script[type="text/template"]').html();
container.setTemplate(template);
container.processTemplate(data);
}
使用示例
<script>
//加载数据
tool.loadData("notice",data);
</script>
<ul class="app-ul" id="notice">
<script type="text/template">
<li>
<label>标题:</label>
<input type="text" id="title" value="{$T.title}"/>
</li>
<li class="many-imgLi">
<label>图片:</label>
<div class="many-imgDiv">
{#foreach $T.paths as src}
<div>
<img data-path="{$T.src}" src="{config.apiUrl + $T.src}"/>
<i class="iconfont icon-minus" onclick="deleteImg(this)"></i>
</div>
{#/for}
<div id="addImgDiv" onclick="mui('#select-div').popover('toggle');">
<img src="../../../static/img/add-images-01.png"/>
</div>
</div>
</li>
</script>
</ul>
2.动态渲染:对于页面某些容器需要重复被渲染,而使用JTemplate方式,渲染一次后页面原先的模板代码已被替代,所以我模拟Jtemplate的方式,写了如下渲染后的页面元素html代码,从而可以动态赋给页面,而模板代码放在另一个隐藏div中。
/* @target 通过获取加载数据后的html代码
* @param tem : 待加载数据的模板代码
* @param data : 加载的数据
*/
tool.getLoadHtml = function(tem,data) {
var arr = tem.match(/{.*?}/g);
for(var i in arr) {
var s = arr[i].replace("$T","data").
replace("{","").
replace("}","");
tem = tem.replace(arr[i],eval(s));
}
return tem;
}
3.动态渲染升级:上述方法未能完全模拟JTemplate,后细思,JTemplate本身也可以动态加载。只需要将模板代码放在隐藏div容器中,并获取html代码保存在js变量tem中,每次在隐藏div渲染完获取html代码放入页面,再将原先tem的值赋会隐藏div中,如此可重复渲染。
4.时间日期相关
/* @target 计算当前日期减目标日期相差几年几月几天
* @param someDay : 目标日期
* @return "xx岁xx月xx天"
*/
tool.minusDate = function(someDay) {
if(someDay==null || someDay=="") {
return "";
}
if(typeof someDay == "string") {
someDay = new Date(someDay);
}
var date = new Date();
//当前年月日减该日期年月日
var y = date.getFullYear() - someDay.getFullYear();
var m = date.getMonth() - someDay.getMonth();
var d = date.getDate() - someDay.getMonth();
//日期或月份为负数则向前借位
if(d<0) {
m--;
d += 30
}
if(m<0) {
y--;
m += 12;
}
return y+"岁"+m+"月"+d+"天";
}
/* @target 计算目标日期减当前日期相差几天
* @param someDay : 目标日期
* @return 相差天数
*/
tool.minusToday = function(someDay) {
if(someDay==null || someDay=="") {
return -1;
}
if(typeof someDay == "string") {
someDay = new Date(someDay);
}
//该日期的毫秒数
var someTime = someDay.getTime();
//当前日期00:00:00时刻的毫秒数
var today = new Date();
today.setHours(0);
today.setMinutes(0);
today.setSeconds(0);
var time = today.getTime();
//毫秒数相减,再除以一天的毫秒数,中向下取整
var day = Math.floor(((someTime - time)/86400000));
return day;
}
/* @target 计算两个日期相差几天
* @param startDay : 开始日期
* @param startDay : 结束日期
* @return 相差天数
*/
tool.minusDay = function(startDay,endDay) {
if(startDay==null || startDay=="" || endDay==null || endDay=="") {
return -1;
}
if(typeof startDay == "string") {
startDay = new Date(startDay);
}
if(typeof endDay == "string") {
endDay = new Date(endDay);
}
//该日期的毫秒数
var startTime = startDay.getTime();
var endTime = endDay.getTime();
//毫秒数相减,再除以一天的毫秒数,中向下取整
var day = Math.floor(((endTime - startTime)/86400000));
return day;
}
/* @target 根据某日期,获取所在周的某一天的日期
* @param someDay : 目标日期
* @param index : 序号,1~7代表周一至周日
* @return 周几的日期字符串
*/
tool.getWeekDay = function(someDay,index) {
if(typeof someDay == "string") {
someDay = new Date(someDay);
}
//获取日期和周序号
var date = someDay.getDate();
var weekday = someDay.getDay();
if(weekday==0) {
weekday = 7;
}
//重设日期
someDay.setDate(date-weekday+index);
return tool.getStringDay(someDay);
}
/* @target 根据某日期,获取其对于周几
* @param someDay : 目标日期
*/
tool.getWeekByDay = function(someDay) {
if(typeof someDay == "string") {
someDay = new Date(someDay);
}
var week = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
var index = someDay.getDay();
return week[index];
}
/* @target 根据某日期,获取对应字符串
* @param day : 目标日期
* @param split : 分隔符
* @return 日期字符串
*
*/
tool.getStringDay = function(day,split) {
//没有指定,默认以.连接
if(!split) {
split = ".";
}
var year = day.getFullYear();
var month = day.getMonth()+1;
var date = day.getDate();
if(month<10) {
month = "0" + month;
}
if(date<10) {
date = "0" + date;
}
return year + split + month + split + date;
}