stoneniqiu 理想就是自己喜欢做,并对社会和他人都有意义的事情!
H5嵌入原生开发小结----兼容安卓与ios的填坑之路
2016-11-19 08:29 by stoneniqiu, 1038 阅读, 8 评论, 收藏, 编辑
一开始听说开发H5,以为就是做适配现代浏览器的移动网页,心想不用管IE了,欧也。到今天,发现当初too young too simple,兼容IE和兼容安卓与IOS,后者让你更抓狂。接下来数一下踩过的坑。主要分UI展示,键盘,输入框等等。解决bug最苦恼的问题不是没有解决方案,而是你没有找到真正的原因。再就是现象难以重现,每次都要发布代码,然后到手机app中去测试,模拟。这些地方会耗费大量的精力。
一、UI相关
1.安卓4.4以下不支持fixed布局。
fixed布局的作用之一就是在手机键盘弹起来的时候,可以自动把页面顶起来。如果不支持的话,换绝对定位也是可以的。但是绝对定位某些机型比如sm-n7508,华为m7上还是没有能顶起来。IOS没有这个问题。
2.小于1px显示问题
部分安卓机器(比如小米)的分辨率低,如果border的宽度小于1px。安卓机出现一种边框消失了的现象。样式上有点奇怪,IOS没有这个问题。
一开始以为是别的元素挡住了,但是调了半天无解。最后突然意识到是不是计算出来的高度有小数导致的。然后马上取整:
$target.css("height", Math.ceil(maxline * lineHeight));
但是,华为的某些类型的是上面显示不正常,出来一排点点。
再修正一下:
$target.css("height", Math.ceil(maxline * lineHeight) - 1);
或者用floor。你好奇为什么会有小数高度呢,因为这个功能设计一个折叠,需要重新计算dom的高度。
二、键盘相关
1.ios键盘挡住输入框。
这个发生的频率很高,中文输入法或者输入法切换的时候会遮挡。
解决的办法如下:

setInterval(function () {
if (document.activeElement.className.indexOf('inputcontent') >= 0) {
document.activeElement.scrollIntoViewIfNeeded(); }
}, 300);

这是最管用的办法,inputcontent为输入框的样式。activeElement表示获得焦点的元素。但是这个方法只在app中有用,如果是在浏览器中还是会失效。
2.键盘收下留下空白阴影。
这个在部分安卓机上比较明显,当键盘在激活状态,突然来一个模态弹框,很明显的看到键盘收下去之后出现了一个短暂(不到1秒的样子)的空白,然后页面再收下去,让人感觉闪了下。比如华为P7。但是ios上没有关系,这个问题没招,系统不流畅。
3.无法保持键盘在弹出状态。
web其实无法直接控制键盘,只有通过让输入框获focus来让手机的键盘弹出来,但是三星SM-N8507v 这款就是不听话。我也无解了。
三、输入框相关
1. fastClick 锁住输入框。
在ios中,会出现几秒的输入框没有反应,开始也怎么想不明白,各种尝试,推测,搜索发现原来是使用的轻框架中用到了fastClik引起的,解决的办法就是加上一个样式。
<div id="content" class="inputcontent needsclick" ></div>
解决方法到是简单,但是当初为找到这个原因,费了好大劲,把框架的模块一个一个删,最后才定位到。如果不加这个,不单会锁住输入框,每次调用focus都会设置光标跑在最前面,无法移动到后面。这个体验很糟糕。
2.模拟placeholder。
div作为输入框,本身加入placeholder是无效的。得借助于伪元素。
<div id="content" class="inputcontent needsclick" placeholder="有问题就尽管提问吧" contenteditable="true"></div>

.tools .inputcontent:after {
display: inline-block;
width: 100%;
color: #999;
content: attr(placeholder);
}

然后在获得焦点和失去焦点的时候对这个属性进行移除和添加操作。这样做的好处在于,分离用户输入的内容,如果把placeholder的值直接在写输入框中这样会多一些判断,让代码不太干净。
3.div的换行是div
在div中触发换行,会得到一个div。这个就相当于是在编辑器中。而不是我们认为的<br>或者换行符。
所以,需要对div进行过滤替换。

var replace = /<div.*?>(.*?)<\/div>/g;
txt = txt.replace(replace, function(a) {
if (a != "<br>") {
return "<br>" + delHtmlTag(a);
}
return delHtmlTag(a);}

4.粘贴莫名奇妙带了样式
在输入框中粘贴会以这样的形式出现:
<font style='font-size:30px;color:#999'><span>粘贴内容</span></font>
不清楚是系统还是app定义的。所以也得过滤。 用户还可以粘贴其他文章,容易搞乱输入框中的样式,需要加上:
.tools .inputcontent *{font-size: 0.50rem !important; color: #000 !important;line-height: 22px !important;font-weight: normal !important;}
因为如果从粘贴事件里面处理的话,容易搞乱焦点,让焦点在最前面。这样很不爽。所以还是样式控制,在发送的时候过滤掉所有的标签。
5.超出遮挡/换行遮挡
这是一个神奇的bug,当内容超过div的最大高度后,最后一行出现一个神奇的现象,头两个字显示了,后面的内容不见了(快快后面其实有内容),直到下一次换行才会出现。
我alert里面的内容,发现并没有其他的元素,我不断的尝试,发现div overflow: hidden;的时候字都会显示出来,但是为了让用户能够在内容框里面上下滚动。我得让y轴是可以滚动的:overflow-y: auto; 所以应该是滚动条引起的。但我确实不知道如何修改。后来试出一个hack的方法。只要有一个换行就不会出现这种情况。所以,我就在用户输入到特定行的时候就塞进一个1px的换行:

if ($("#content").height() == 88 && isIOS() && !haveAppendBr) {
$("#content").append("<div style='height:1px;border-top:1px solid #fff' ><br></div>");
haveAppendBr = true;
}

当然这不是正规的解决办法,如果园友有遇到相似的剧情,可以赐教一下。
6.安卓第一次不能换行
这个现象是消息发送成功之后,用户(小米)一来就是点换行,却无法换行,我怀疑是安卓系统阻止了这样的行为。但是在输入一个字之后,换行就是正常的了(哪怕再删掉这个字)。ios里面没有这个问题。开始我尝试去人为加一个换行,又发现焦点没了。想想这样问题不改也罢。
7.输入框光标闪动
这个是translate3d属性引起,修改sm框架中的一段代码设置useTranslate为false。位于handleTouchMove方法中。
四、图片相关
1.安卓不能上传。
安卓很多时候都不能触发input type='file'的弹框,上传就得走原生的帮助。原生拦截到链接后就会弹出图片选择框。
window.location = 'xxapp:h5Upload({"openType":2,"needChop":false,"uploadUrl": '+fileUploadUrl+',"key":' + totalFiles + ',"callbackMethodName": "uploadComplete"})';
key是为了记住是第几张图片,便于在原生上传结束之后把地址和key一起传到uploadComplete方法中。这样界面上才可以做相应的修改。但这不是我说的重点。重点是Url不要带中文啊或者特殊符号之类的。一方面很多手机里面的图片命名很奇怪,一大堆,像在uc上面保存下来的图片后面跟了几个类型。这种名称没啥用,非常建议服务器端像微信一样处理上传图片,成功之后得到一个唯一的字符串就行。不然有的系统会自动解码你得区分的用上了encodeURI或者encodeURIComponent。测试妹子会说这个手机可以,那个不可以,然后是苦了前端。
2.图片转了90度。
安卓部分机型(小米2A,三星N7,三星G9)对于拍照的图片上传之后居然左转了90度。
(非原图)
我把照片发出来之后,放在桌面上也是歪的,拍摄的图片本身会带有一个exifdata,这个对象里面包含了拍摄的时间、方向、曝光时间等一些信息。用exif.js可以看出来。也有网站可以直接查看。

function getdata(id) {
EXIF.getData(document.getElementById(id), function () {
var data = EXIF.getTag(this, 'Orientation');
console.log(data);
});
}

思路就是通过这个方向来判断是否给图片来个再旋转。
this.style.transform = 'rotate(' + current + 'deg)';
3.图片半截
这个问题在安卓上面会有,不是加载的问题。正确的效果图片应该是垂直居中的。但不知道为什么偶尔的会只出来个半截。而且我发现,给图片设置百分比,手机和pc不一样,手机图片的百分比并不是相对于其父类元素,而是它自己。
所以图片的宽度会超出其父类,即使<div><img></div>的宽度都是100%。overflow:hidden吧,图片可能显示不全。超出的部分会导致用户可以在图片上面左右滑动,这在ios中有个搞笑的现象,就是对弹出的图片不断的左右滑动,再恢复后居然能让原先绑定的点击事件失效,不确定是框架的原因还是系统的原因。当时是用一个模态框改造的。最后干脆自己再写一个:

Client.modalImg = function (src) {
if (!src) return;
if ($(".img-overlay").length) {
$(".img-overlay").remove();
};
var modal = '<div class="img-overlay"> <div class="imgheader"></div> <div class="imgbox"><img onload="reCalcuImg();" src="' + src + '" /></div>';
$("body").append(modal);
}; //校准位置
function reCalcuImg() {
var headerH = $(".imgheader").height();
var boxH = $(".imgbox").height();
var imgH = $(".imgbox img").height();
var realMaxH = boxH - headerH;
// console.log("headerH", headerH, "boxH", boxH, "imgH", imgH, "realMaxH", realMaxH);
if (imgH > realMaxH) {
$(".imgbox img").css("height", realMaxH + "px");
console.log("大于最大高度,realMaxH", realMaxH); } else {
var gap = (realMaxH - imgH) / 2;
// console.log("小于最大高度,margintop",(realMaxH - imgH), gap);
$(".imgbox img").css("margin-top", gap + "px");
}
}

写在onload事件结束后是确保图片已经加载完成。这样才能计算,如果直接在modalimg中计算,图片的高度可能为0。然后如果图片的高度大于最大高度则设置为最大高度,否则的话在进行margin,让其垂直居中。
五、消息
1.websocket是脆弱但又顽强的。
websocket很容易受到网络的影响而中断,但网络一恢复能自动重连。而手机会有切到后台运行的这种情况,比如小米系统会在手机黑屏之后把网络断掉,用户进入应用的时候,你得有重连的机制,确保消息没有遗漏。
socket.on("reconnect", function () {
isConneted = true;
eventManger.trigger("reconnect");
listenChannel();
});
在listenChannel中通过 socket.emit 告之node后端重连了,拿消息的姿势调整下。
but红米手机有一款socketio老是重连,所以手机上也要准备轮询的机制。重连三次关掉socket,直接轮询。
2.消息先发后到。
先发的消息后到,这是很有可能的,但是用户就会奇怪。比如一条长消息分成几次发,前端可以在前一条发完了再发第二条。

var limit = 1000;
function loop(i) {
if (i < num) {
send(content.substr(i * limit, limit), function () {
i++;
loop(i);
});
}
};
loop(0);

六、前端的一些思考
那天走在路上想,前端是个什么样的职位,会JavaScript,node,熟悉mvvm,html5特性就ok了吗,其实技能只占到一部分。前端相当于是个连接者,产品经理的想法,美工的设计,后端程序员的接口实现,客户的期待,测试妹妹的重点,领导巡视的对象,大部分都汇集在前端完成的页面上,所以沟通,理解能力比较重要。产品经理和测试也会容易太专注于界面效果而忽略整个系统的分配合作。有时候看到界面或者流程不对,可能是后端的问题,你得去推。就像看见一人面有难色,其实体内已经有病了,所以你得会表达,表达问题在哪,或者表达需要怎样的协助;而在面对bug的时候要清楚哪些是功能性的bug,哪些是体验性的bug,基本功能必须保障正确,体验性的问题凡是影响基本功能的使用的都是严重的体验性bug,但bug总是有的,不太可能做到所有机型都一样。这里面还有时间成本,你解决一个不太重要的bug可能会花上很长的时间;再就是分析思考,各种不正常现象如何找到原因,除了依赖于经验你要坚信所有妖魔鬼怪都是有出处的,每个界面都可能有自己的差异性,不正常的现象重现的条件是什么,有哪些相关因素,然后顺藤摸瓜;再就是代码能力,尽量保证模块的独立和职责的单一,这个方面细节很多,是每个程序员需要注意的地方。最后就是想说,神奇的bug还不止这些,因为缺少这方面的开发经验和知识储备所以花了很长时间,远超自己的预估。文中如有不当或更好的方法还请指出。
你的关注和支持是我写作的最大动力~
书山有路群:452450927
出处:http://www.cnblogs.com/stoneniqiu/
github:https://github.com/stoneniqiu
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面
stoneniqiu 理想就是自己喜欢做,并对社会和他人都有意义的事情!的更多相关文章
- <<你最喜欢做什么--兴趣问题清单>>总结
二.测试作业 你最喜欢做什么--兴趣问题清单 •根据迄今为止已有的经历,你真正喜欢从事的工作是什么? 目前还没有接触工作,就工作而言,凭自己所学的本领和技术去工作,我认为我会喜欢我所做的工作 •休 ...
- 今天发现之前瑞乐做的登录和注册居然都是用的get请求,瞬间出了一身冷汗.
今天发现之前瑞乐做的登录和注册居然都是用的get请求,瞬间出了一身冷汗. 然后迅速的让晓勇改成post请求了. 不然我觉得凡是有点抓包能力的人抓到我们登录和注册这么涉及安全的东西居然用的是get请求, ...
- Highcharts做柱状图怎样样每个柱子都是不同的颜色显示
series: [{ data: [{'color':'#F6BD0F','y':11}, {'color':'#AFD8F8','y':12}, {'color':'#8BBA00','y':13} ...
- 三步将Node应用部署到Heroku上 --转载
Heroku是一个提供快速部署服务的云平台.支持Node,Ruby,Java,PHP,Python,Go多种语言,今天体验了下,简直不要太爽.下面简单的介绍一下. 首先还是要注册一个账号:https: ...
- MEAN栈开发
Nodejs之MEAN栈开发(二)----视图与模型 2016-06-02 08:30 by stoneniqiu, 92 阅读, 2 评论, 收藏, 编辑 上一节做了对Express做了简单的介绍, ...
- 为什么很多人坚信“富贵险中求”?
之家哥 2017-11-15 09:12:31 微信QQ微博 下载APP 摘要 网贷之家小编根据舆情频道的相关数据,精心整理的关于<为什么很多人坚信"富贵险中求"?>的 ...
- 我眼中的自己ps:自我介绍
我是一个理科生,学的是计算机科学与技术专业,目前在桂林理工大学信息科学与工程学院就读.我心里不是很喜欢这个专业,但是因为当初的某种原因就入了这个门.自从学习了计算机以后,我发现这个专业可谓“博大精深, ...
- c++101rule
组织策略0,不拘于小结缩进, 行的长度,命名,注释,空格,制表,1-4,高警告级别干净利落地进行编译,使用构建系统,使用版本控制,代码审查风格5,一个实体应该只有一个紧凑的职责. (依赖性管理,继承, ...
- 深度剖析 | 基于大数据架构的BI应用
说起互联网.电商的数据分析,更多的是谈应用案例,如何去实践数据化管理运营.而这里,我们要从技术角度分享关于数据的技术架构干货,如何应用BI. 原文是云猴网BI总经理王卫东在帆软大数据上的演讲,以下是整 ...
随机推荐
- java 与c#比较
1.开发周期方面:c#比java开发周期更快2.java出现的时间更长.开源性广.跨平台性好3.c#较为封闭.后出于java4.c#有无符号类型.java没有5.java与c#都有值类型.但是java ...
- 一整套WordPress模板制作的教程
WordPress基本模板文件 一套完整的WordPress模板应至少具有如下文件:style.css: CSS(样式表)文件index.php : 主页模板archive.php : Archive ...
- 20145337 《Java程序设计》第五周学习总结
20145337 <Java程序设计>第五周学习总结 教材学习内容总结 第八章 JAVA中的所有错误都会被包装成对象,如果你愿意,可以尝试执行并捕捉代表错误的对象后做一些处理.使用了try ...
- BizTalk开发系列(三十三)BizTalk之Excel终极解决方案
Excel作为优秀的客户端数据处理程序得到了广泛的应用. 由于其简单又强大的功能在很多公司或个人的数据处理中占用非常重要的位置. 而BizTalk作为微软的SOA主打产品虽然免费提供了很多Adapte ...
- 四则运算之C++实现篇
对四则运算的一些要求如下: 1.题目避免重复:2.可定制(数量/打印方式):3.可以控制下列参数: 是否有乘除法.数值范围.加减有无负数.除法有无余数.否支持分数 (真分数, 假分数, …): 一 ...
- Android课程---第一课
Android是一种基于Linux的开源的操作系统 主要使用于智能设备,如智能手机.平板电脑和智能电视等 由Google公司领头开发并推广,2008年推出第一个版本. 此系统最初由”安卓之父" ...
- graph | hungary
匈牙利算法,求二分图最大匹配. 若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径.(M为一个匹配) 由增广路 ...
- eval 与 Function
var json='{"name":"lee","age":"15"}' function test () { var ...
- 使用eclipse开发servlet
package cn.itcast; import java.io.IOException; import javax.servlet.GenericServlet; import javax.ser ...
- 【iCore3 双核心板_FPGA】实验十七:基于I2C总线的ARM与FPGA通信实验
实验指导书及代码包下载: http://pan.baidu.com/s/1dFqddMp iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...