最近开发移动端较多,整理了一下最近遇到的一些兼容问题
1.1px在移动端的解决方案
最开始当然从移动端的兼容性适配开始了,关于的详细解释,在我上一篇博客中已经大概讲了一下,1px在移动端的解决方案,问题产生的原因就是在于不同dpr的设备上,1px的css样式像素会产生不同的效果。
- 对于老项目,最好的解决方案可以使用css3中的transform结合伪类::after/::before来进行缩放解决;
- 对于新项目,可以使用viewport+rem,可以全局性的设置缩放比例,并设定全局根元素的rem,
头部的原始状态设为:
<meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
js动态修改的部分:
var viewport = document.querySelector("meta[name=viewport]")
if (window.devicePixelRatio == 1) {
viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')
}
if (window.devicePixelRatio == 2) {
viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')
}
if (window.devicePixelRatio == 3) {
viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')
}
var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
详情可以移步这里
2.当字号小于12px时,安卓中文字无法垂直居中
3.移动端实现,键盘点击,用户唤起搜索功能(即enter键?)
<form action="javascript:void(0)">
<input
name="search"
v-model="searchValue"
placeholder="请输入公司简称或产品名称"
ref="searchInput"
@keyup.13="searchAllData()" />
</form>
Tips:
- 不管是安卓还是苹果手机,搜索按键的keycode都是13,这里是vue项目,可以使用按键修饰符。
- 用type="search"来统一安卓和苹果机的搜索按键。
- 必须在input标签外面套上form表单,并设置 action=“javascript:void 0”,action属性很关键,才能实现搜索功能,不能省略。
- 若想添加自动聚焦功能,可以先获取当前input这个dom元素,再添加focus()方法;
this.$nextTick(() => { this.$refs.searchInput.focus() })
4.当使用position定位时,css3中transform的等级高于position定位
里面涉及到对于层叠上下文的知识理解,具体可以参考鑫旭大大的博客
5.safari浏览器(包含ios的微信浏览器,一个内核)在ios中返回上一级不会刷新页面,但是安卓会重新刷新页面
(1)针对这种问题,当时的产品的方案是要保留缓存,返回上一级页面时,会记住用户的筛选记录,对于安卓端的刷新页面的现象,当时的解决方案是将用户的筛选条件记录在sessionStorage里面,当返回上一级页面时,从缓存中读取记录,并重新请求。在监听用户跳转页面的行为中,存在两种情况:
- 一种是vue内置的vue-router路由跳转
- 一种是js里面使用window.lcaotion.href跳转
针对这两种跳转方式,在使用监听事件onbeforeunload时,引出了兼容性问题8
(2)针对safari不想留住缓存的情况,渴望刷新,新增解决方案:
监听页面的pageshow事件
if(isIOS()){
window.addEventListener('pageshow', function (event) {
if (event.persisted || window.performance &&
window.performance.navigation.type == 2)
{
location.reload();
}
},false);
}
6.微信内置浏览器深层嵌套一层webview,ios导致偶尔会出现滑动到底部,下滑困难,内部无法滑动,需要倒退1px才可以
这个问题同理滑动到顶部,会出现上滑困难,内部无法滑动,需要倒退1px才可以。
解决方案:在于这个1px上面,废话不多说,上代码!
/**
* 判断是否为ios
*/
export function isIOS () {
return !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
}
/**
* 微信浏览器判断
*/
export function isWXBrowser () {
var ua = window.navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) == 'micromessenger') return true
return false
}
// 重点在这里哦,微信环境ios下触底或者下拉回弹1px
/**
*
* 微信浏览器 IOS 容器内滚动到底或到顶,再次快速滑动会出现无法滑动的bug
* @export
* @param {obj} e 容器的节点
*/
export function fixIosScroll (e) {
if (!isIOS && !isWXBrowser) return
const scrollHeight = e.scrollHeight
const scrollTop = e.scrollTop
const clientHeight = e.clientHeight
// 滚动条在顶部,回退1px
if (scrollTop === 0) {
e.scrollTop = 1
return
}
// 滚动条触底,向上1px
if (scrollHeight - scrollTop === clientHeight) {
e.scrollTop = scrollTop - 1
}
}
7.微信分享功能,偶现初始化失败,默认会直接分享当前window.location页面,使用vue中的路由router跳转无法获取当前页面。
针对微信jssdk的初始化失败的情况,vue项目中无法默认分享当前页面,解决方案是,跳转当前需要分享的页面时不使用vue-router路由跳转,而是window.location,href跳转,改变window.location的值,实现初始化失败时默认分享当前页面
8.微信浏览器移动端不支持window.open打开新的窗口,不支持onbeforeunload页面卸载事件
在监听页面地址变化的时候,我开始使用的是onbeforeunload事件,用来针对vue-router跳转和window.location.href跳转两种情况都很有效果。是在使用谷歌浏览器内置的移动端模拟器上面是ok,ok,ok……的,But……(黑脸表情。。。)当我在手机上面真机调试的时候,竟然不起作用,没有效果!!!!
所以,我不得不放弃了这个onbeforeunload,??
最后,分成了两种来判断,vue-router跳转使用路由内置的钩子函数beforeRouteLeave来添加(这个监听不到window.location.href跳转哦);
window.location.href则在添加跳转的事件里面捕获;
另外,提一嘴,H5新增的历史记录监听事件,通用性感觉不高:
- window.onpopstate:当调用history.go()、history.back()、history.forward()浏览器的几个前进后退时触发;pushState()\replaceState()方法不触发
- window.onhashchange:当前 URL 的锚部分(以 ‘#’ 号为开始) hash值发生改变时触发
另外补充一点:
使用onpagehide可以检测浏览器页面的关闭事件触发,以及监听页面window.location.href的跳转事件,但是对于vue的单页面router跳转是捕捉不到的,可以使用destoryed或者beforeRouteLeave路由的钩子函数来监听
或者onunload也是可以尝试使用的方法之一
9.当使用input输入框输入时,ios出现软键盘后,页面会被顶上去,收起键盘,页面下方留白
10.微信H5中ios有页面回弹的效果,安卓没有
11.在移动端浏览器中(至少在微信环境中),打开http://XXXX.pdf预览pdf文件,ios可以直接预览,安卓必须先跳转浏览器下载后才能看
解决办法:引入pdfh5.js插件,跳转另外一个html网站的链接页面,在这个页面中创建一个dom,支持使用canvas和svg两种渲染模式,进行预览
npm install --save pdfh5
<template>
<div id="app">
<div id="demo"></div>
</div>
</template>
<script>
import Pdfh5 from "pdfh5";
export default {
name: 'App',
data() {
return {
pdfh5: null
};
},
mounted() {
//实例化
this.pdfh5 = new Pdfh5("#demo", {
pdfurl: "../../static/test.pdf"
});
//监听完成事件
this.pdfh5.on("complete", function (status, msg, time) {
console.log("状态:" + status + ",信息:" + msg + ",耗时:" + time + "毫秒,总页数:" + this.totalNum)
})
}
}
</script>
//*********************************或者js引入****************************
//1.引入css
<link rel="stylesheet" href="css/pdfh5.css" />
//2.创建div
<div id="demo"></div>
//3.依次引入js
<script src="js/pdf.js" type="text/javascript" charset="utf-8"></script>
<script src="js/pdf.worker.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/pdfh5.js" type="text/javascript" charset="utf-8"></script>
//4.实例化
var pdfh5 = new Pdfh5('#demo', {
pdfurl: "./default.pdf"
});
12.ios微信首次打开h5页面,底部是没有历史记录导航的,如果这时候直接跳转外链,再返回,这时首页底部就会增加历史记录导航,而且出现的问题是》》》》遮挡首页底部部分内容(商城首页)
解决办法:
手动增加一个空的历史记录
/**
* 判断是否为ios
*/
export function isIOS () {
return !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
}
/**
* 微信浏览器判断
*/
export function isWXBrowser () {
var ua = window.navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) == 'micromessenger') return true
return false
}
if (isIOS() && isWXBrowser()) {
window.history.pushState({}, '', '')
}
13.苹果iOS11,iphoneX以上存在安全区域兼容适配
事故源自于一次App中内嵌H5网页,h5页面底部出现一条灰色的空白区域,当底部弹出选择框时,被这个灰条挡住下面的一部分,考虑是iphoneX机型,故可认定为安全区域的阻挡,同样的,在iphone6机型中就无此问题。
解决办法:
在html文件中设置头部的meta,viewport-fit设置为cover
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
在被遮挡的弹出层上设置
padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */
因为项目是老项目,设计到的页面比较多,故没有全局的body去设置,哪个页面出现问题就用这个办法去解决。但是移动端新的项目在做开始的适配的时候,建议全局设置safe-area-inset-bottom
14.ios在微信浏览器中的h5网页有页面的回弹效果,若页面中存在轮播的swiper组件,滑动过程中会出现页面抖动
话说这个问题我找了好久,开始还以为是偶现问题,后来一顿操作排除发现不太对,这尼玛只要你滑到底部,手暂停一下不松手,页面的抖动就出现了,而这个抖动和轮播下一张图片是一起出现,故定位到了问题的根本所在!!!
解决办法: 监听页面的滑动事件,在滑动触发的时候,停止轮播的动画,OK~~ fine next!
15.offsetLeft和offsetTop的使用
offsetLeft值跟offsetTop值的获取跟父级元素没关系,而是跟其上一级的定位元素(除position:static;外的所有定位如fixed,relative,absolute)有关系,是距离上一个使用定位元素的距离
16.scrollTo(0,0)和scrollTop=0
苹果低版本的手机上不支持获取使用dom.scrollTo(0,0),使用该方法会报错。
换言之,使用dom.scrollTop=0,就可以正常使用
17.app内嵌H5,当app在后运行时,h5页面的所有js进程都会被停止。
比如当我在内嵌的H5页面写一个定时器时,当我回到桌面,(这里并非是杀掉app,而是后台运行app),定时器就会暂时停止。只有当我回到app里面,定时器就会接着刚才的进程继续打印(这里并非是从头执行,而是接着执行)
18.移动端文字实现两端对齐,使用text-align-last在ios会有兼容性问题
使用text-align-last:justify;在安卓上面表现没有问题,但是在ios上面不会对齐。
解决办法:在当前的元素后面添加一个after伪类,并给当前的元素设置行高为0,如下:
span{
text-align: justify;
text-align-last: justify;
line-height:0px;
&::after{
content:"";
width:100%;
display:inline-block;
}
}
如此,安卓和ios都可以很好的兼容
19.移动端安卓和ios对于格式化时间new Date()日期格式的处理兼容性问题
const strTime="2018-1-1 9:10:10";
const myDate = new Date(strTime);
const Y = myDate.getFullYear();
const M = myDate.getMonth()+1;
const D = myDate.getDate();
const curDay = Y + '-'+ M + '-' + D;
console.log(curDay)
// 输出结果:Android系统:2018-1-1 iOS 系统:NaN-NaN-NaN
明显ios对于格式化时间new Date()的不兼容
解决办法:
const strTime="2018-1-1 9:10:10";
var date= new Date(Date.parse(strTime.replace(/-/g, "/"))); //转换成Data();
使用字符串的替换,将 ”-“替换为 ”/“,这样ios和安卓就都可以支持了
20.安卓和ios在调用微信的jssdk的时候的区别,批量隐藏\显示菜单时灵时不灵问题
安卓:当你在当前页面使用wx.hideMenuItems(),会把你想要隐藏的菜单隐藏起来,当你跳转到新的页面时(也就是重新调用wx.config后),你的隐藏了的菜单又会被重新显示出来,需要重新调用wx.hideMenuItems(),再次把你想要隐藏的菜单隐藏起来
ios:当你在当前页面使用wx.hideMenuItems(),会把你想要隐藏的菜单隐藏起来,当你跳转到新的页面时(也就是重新调用wx.config后),你在上一个页面隐藏的菜单还会继续保持隐藏的状态。如果这个时候你想让之前隐藏的菜单展示出来,就必须调用 wx.showMenuItems() 方法去设置要显示出来的菜单,才能实现这个需求
其他端兼容性问题总结:
1.在当前页面(这里指的pc端)使用iframe嵌套其他域名下的子页面时,父子页面跨域通信,使用postMessage方法,第一次调用会执行一次,第二次会执行两次,第三次会执行三次……
解决iframe父子跨域postMessage进行通信时,开始我使用的监听方式是window.addEventListener(‘message’, (e) =>{ });监听到的message事件就会有多次触发的场景。
后面网上查询,没有找到很明确的解释。但大概意思就是多次调用addEventListener(‘message’, (e) =>{ })会生成多次不同的匿名函数e,后面每一次调用这个监听方法,就触发前几次生成的匿名函数,而且匿名函数的数据都是前几次的旧数据,不会被新数据更新。有点类似于生成了一种旧数据缓存的机制。
解决这种现象:
使用window.onmessage=function(e) { };对message事件进行监听就可以了,就酱~~~
2.html2canvas 在ios15系统中生成海报图片的过程中含有页面空白问题
html2canvas 生成海报的时候,含有中文的元素在ios15系统上直接白屏生成失败,经过排查,去原仓库下面提issue后发现是ios15系统字体的问题,给中文字体设置如下字体可解决:
.text{
font-family: Helvetica, Tahoma, Arial, 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC', STXihei, 'Microsoft YaHei', SimHei;
}