APP开发

一.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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值