工作需要,用HTML5写一个微信的内置网页,是一个参会报名流程。上次写html还是上学时交作业,现在着实有些手忙脚乱了,现学现用、磕磕绊绊,项目总算告一段落,到了要总结一下的时候了。简单记录了做这个项目时所遇到的问题,有些问题在网上能搜到解决办法,有些问题是为了实现效果耍的小聪明。

工具以及框架

由于我只负责h5界面(让我负责java后台也做不来。我对好多语言都有兴趣,对java就是提不起兴趣,或许是因为大学学java学烦了。),所以就用了HBuilder只码web界面,这个开发工具开发h5网页来说很便利,比如它有代码提醒、边改边看模式、手机端网页运行、运行到iPhone上等等功能,但也有不好用的地方,比如快捷键、搜索方式等。

还有开发微信内置web网页必不可少的工具:微信web开发者工具。很不幸的说开发到中期才发现这个工具,明明就在微信JS-SDK下面就是视而不见。目前这个工具已经升级为开发小程序专用编译器,不能调试微信内置web页面。

当然还有谷歌浏览器Google Chrome,浏览器来说,我之前是火狐党,开发这个项目才用了谷歌浏览器。谷歌的开发者工具挺好用的,有错误调试,样式修改,多种手机屏幕调试。还有微信JS-SDK说明文档火狐浏览器上目录点击无效,谷歌浏览器就可以调转到相应内容。还有一点,项目中用到了一个别人写好的picker控件,在火狐浏览器上打开一团糟,谷歌浏览器完美运行,幸运的是微信内置浏览器也运行无误。重点说明:我不是火狐黑,项目之外依旧继续用火狐。这时可以感觉到web开发做浏览器兼容还是有很多工作的。

开发微信用的东西肯定要用微信提供的开发样式库WeUI,毕竟风格相近直接拿来用就行,即便是不一样,改起来也方便很多。包括微信的JS-SDK的demo示例代码

还有号称最接近原生APP体验的高性能前端框架MUI,项目中的picker就是用的这里的。

微信分享调用和地图功能

分享功能重写,调用地图

微信分享和地图调用都使用了微信提供的JS-SDK,公众平台有详细的说明文档。这里只记录一些调用步骤和遇到的问题。

微信分享不用单独去写,微信内置网页右上角会自动加入分享功能,默认分享出去的网页样式标题为页面标题,图片为网页中第一张图片,简介也是第一段文字。如果想自定义这些样式内容,就需要重写分享方法。

引入js文件,建议调用https的js地址,如果页面启用了https,使用http的js地址在iOS9中将无法调用sdk

1
<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript"></script>

调用config方法,配置权限验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
wx.config({
debug: true,//开启调试模式,一直有alert出现。发布页面时改为false
appId: 'wx1234567890032222',//微信公众号唯一标示。
timestamp: timestamp,//时间戳
nonceStr: nonceStr,//随机串
signature: signature,//签名
jsApiList: [
'checkJsApi',//验证客户端版本是否支持sdk
'onMenuShareTimeline',//分享朋友圈
'onMenuShareAppMessage',//发送给朋友
'openLocation',//地图
'showOptionMenu'//开启右上角按钮内页面分享按钮
]
});
wx.ready(function() {
// 1 判断当前版本是否支持指定 JS 接口,支持批量判断
wx.checkJsApi({
jsApiList: ['getNetworkType', 'previewImage'],
success: function(res) {
}
});
// 地理位置
document.querySelector('#openLocation').onclick = function() {
wx.openLocation({
latitude: 22.537180,//纬度
longitude: 113.976250,//经度
name: 'xxxx酒店',//位置名
address: '地址说明',
scale: 14,//地图缩放级别范围从1~28
infoUrl: ''//在查看位置界面底部显示的超链接,可点击跳转
});
};
// 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
wx.onMenuShareAppMessage({
title: '分享标题',
desc: '分享简介',
link: 'https://www.baidu.com',//分享地址
imgUrl: 'http://oalg33nuc.bkt.clouddn.com/image/wechatshareimg.jpg',//分享图片的地址
});
// 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
wx.onMenuShareTimeline({
title: '分享标题',
desc: '分享简介',
link: 'https://www.baidu.com',//分享地址
imgUrl: 'http://oalg33nuc.bkt.clouddn.com/image/wechatshareimg.jpg',//分享图片的地址
});
wx.showOptionMenu();//显示微信右上角点开的分享按钮
});

这一块前端网页还是比较简单的,因为所需要的签名signature等参数都是后台算好给的。生成签名需要jsapi_ticket,要拿到jsapi_ticket需要access_token,获取access_token的步骤和在iOS原生应用中做微信分享是一样的,拿appidsecret等参数调用接口获取access_token

分享按钮显示/隐藏

分享按钮的显示问题,有时候要求只要指定页面分享出去,其他页面不能要分享,要隐藏掉分享按钮(发给朋友/分享到朋友圈/复制链接/收藏/邮件等等等)。

显示按钮 隐藏按钮

显示的页面需要在wx.configjsApiList:[]里面添加showOptionMenu。并调用wx.showOptionMenu();显示方法。

隐藏的页面需要在wx.configjsApiList:[]里面添加hideOptionMenu。并调用wx.hideOptionMenu();隐藏方法。

有隐藏就要对应有显示,比如第一个页面不作操作默认显示。第二个页面隐藏了,返回第一个页面分享按钮也会被隐藏。所以第一个页面要有显示调用。

MUI的Picker使用问题

调用MUI的Picker

用的MUI框架里的picker,调用起来还是很方便的,layer: 2是联级数量,支持多级picker,如果是单级的layer省略不写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var cityPicker = new $.PopPicker({
layer: 2
});
cityPicker.setData(cityData);
var showCityPickerButton = document.getElementById('showCityPicker');
var cityResult = document.getElementById('selectCityContent');
showCityPickerButton.addEventListener('tap', function(event) {
document.activeElement.blur();
cityPicker.show(function(items) {
alert(items[0].text + ' ' + items[1].text);//点击确认时的选择结果
//返回 false 可以阻止选择框的关闭
//return false;
});
}, false);

PopPicker在软键盘弹出时不能完全隐藏

用的时候还有点问题,在火狐浏览器里,picker的cell都挤在一起了,根本无法滑动。至于是什么原因我也没有研究,因为在微信内置浏览器里可以用。还有另一个bug是不能不改的,iOS中有问题,Android中没问题。就是在输入信息页面,直接点击靠近屏幕下边缘的输入框,页面向上偏移,滑动页面时原本隐藏的picker粗线了。如下左图,右图才是它该有的样子。

picker出现了 正常的样子,不该出现

需要在mui.poppicker.js中增加初始化、show和hide方法中display的改变。解决办法如下,或见iOS键盘弹出后PopPicker出现的临时解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//init构造函数最后增加两行:
self.panel.style.display = 'none';
self.body.style.display = 'none';
//显示
show: function(callback) {
var self = this;
//增加以下2行
self.panel.style.display = 'block';
self.body.style.display = 'block';
self.callback = callback;
self.mask.show();
document.body.classList.add($.className('poppicker-active-for-page'));
self.panel.classList.add($.className('active'));
//处理物理返回键
self.__back = $.back;
$.back = function() {
self.hide();
};
},
//隐藏
hide: function() {
var self = this;
if (self.disposed) return;
self.panel.classList.remove($.className('active'));
self.mask.close();
document.body.classList.remove($.className('poppicker-active-for-page'));
//增加以下2行
self.panel.style.display = 'none';
self.body.style.display = 'none';
//处理物理返回键
$.back=self.__back;
}

MUI的样式mui.min.css与微信的weui.min.css冲突

因为做的是微信内置网页,所以使用了微信提供的weui.min.css样式,在做picker的时候,需要导入MUI的mui.min.css样式。这样一来weui.min.css里的很多div样式被覆盖了,写好的样式变成一团糟。只能放弃使用mui.min.css

因为只用了picker,mui.min.css的作用并不多,只有在picker出现时,后面的半透明蒙版。去掉mui.min.css后,这层蒙版便不再出现了。这个问题还是挺大的,影响交互,picker显示时,还可以编辑输入框。

阅遍mui.min.css终于找到这层蒙版的样式控制,把下面这段css代码拿出来,放到自定义的css样式内即可。

1
2
3
4
5
6
7
8
9
.mui-backdrop {
position: fixed;
z-index: 998;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, .3)
}

iOS第三方输入法遮盖输入框

这是一个非常头疼的问题,之前一直没有发现,因为我根本不用第三方输入法。iOS原生输入法已经很强大了,搞不懂为什么还有人用搜狗百度之流的垃圾输入法,难道仅仅为了皮肤吗?Too naive。

即使用其他输入法,按顺序点击输入框,或者点击网页内弹出的软键盘上面自带工具条上的左右箭头键,切换输入框,这样操作也不会出现输入法遮盖输入框问题。而且这个问题在Android上也不存在。

唯独,一上来就点击页面底下的输入框,第三方输入法弹出缓慢,页面偏移距离计算错误,出现了输入法遮盖输入框的问题。好多网页出现这种问题,比如:各大门户网站的登录界面。

解决办法有点low,但还是比较完美的解决了这个bug,定义js方法:

1
2
3
4
5
6
7
8
9
10
11
<script>
SCROLLY = 300;
TIMER_NAME = 200;
function textfocusClick() {
setTimeout(function() {
if(window.scrollY < SCROLLY) {
window.scrollTo(0, 400);
}
}, TIMER_NAME)
}
</script>

会被输入法遮盖的输入框调用方法:

1
<input id="userNameInput" onclick="textfocusClick()" placeholder="请输入" />

定义的js方法,第三方输入法弹出时window.scrollY的值小于系统输入法弹出的,我大致试验出一个300的值(网络上给出的100等小值根本不行)。如果小于这个值就说明是第三方输入法首次弹出,要偏移页面window.scrollTo(0, 400);,偏移的数值根据需要设定。输入法本身就弹出了,再切换输入框,window.scrollY值会和系统输入法的一样,不会小于SCROLLY,所以不能偏移页面。因为网页会自动偏移,再进行代码偏移,会出现页面闪动。

输入框添加的是onclick点击事件,只有在点击输入框获取焦点的时候才调用,在用工具条上的切换按钮切换输入框焦点时不会调用。

警示框的悬浮显示

警示框不固定在页面上,不随页面滑动而滑动,要求悬浮在导航条下面。

1
2
3
4
5
6
7
<script>
window.onscroll = function() {
var box = document.getElementById("box");
var t = document.documentElement.scrollTop || document.body.scrollTop;
box.style.top = t + "px";
}
</script>

设置警示框div的id为box

1
<div style="position:absolute;width: 100%;height: 45px; left: 0px;" id="box">

placeholder样式

自定义输入框placeholder的文字样式,包括字号大小,字体颜色等,css样式如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* all */
::-webkit-input-placeholder {font-size: 16px; padding-top: 2px;}
::-moz-placeholder { color:#f00; } firefox 19+
:-ms-input-placeholder { color:#f00; } /* ie */
input:-moz-placeholder { color:#f00; }
/* individual: webkit */
#field2::-webkit-input-placeholder { color:#00f; }
#field3::-webkit-input-placeholder { color:#090; background:lightgreen; text-transform:uppercase; }
#field4::-webkit-input-placeholder { font-style:italic; text-decoration:overline; letter-spacing:3px; color:#999; }
/* individual: mozilla */
#field2::-moz-placeholder { color:#00f; }
#field3::-moz-placeholder { color:#090; background:lightgreen; text-transform:uppercase; }
#field4::-moz-placeholder { font-style:italic; text-decoration:overline; letter-spacing:3px; color:#999; }

正则使用

1
2
3
4
var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
if(myreg.test(phoneNumText)) {
alert("手机号正确");
}