6年前端开发整理出的日常开发中碰到的兼容适配问题

5,891 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情


前言

这几天看了一下自己以前写的开发笔记,发现自己也从一个初出茅庐只会面向群编程的菜鸟变成在群里给别人解答问题的老鸟了。正好将自己做前端6年以来碰到的一些项目中很常见的兼容适配问题以及解决方案整理出来分享出来,加快大家进阶老鸟的进度。

1.扩大按钮可点击区域

常见于手机端勾选协议按钮,弹框的"x"号,由于按钮设计的较小,用户手指跟屏幕接触的面积较大,用户需要点击多次才能触发事件,体验较差,需要在不改变ui的前提下扩大按钮的点击区域。

解决:

  1. 使用伪元素(伪元素相对于父元素定位向四周延展,可以设置为任意尺寸甚至脱离原本按钮位置)
.btn {
    width: 16px;
    height: 16px;
    position: relative;
}

.btn::before {
    content: '';
    position: absolute;
    top: -10px;
    right: -10px;
    bottom: -10px;
    left: -10px;
}
  1. 透明边框(这个方案有时候会影响到其他css属性,比如box-shadow、padding、margin)
.btn {
  border: 10px solid rgba(255, 255, 255, 0);
}

2.禁止长按时文字选中,图片唤醒原生按钮

常见于手机端需要长按的操作,比如长按保存海报如果点击区域不在海报范围内,点到文字上会触发复制,点在其他图片上会触发原生的按钮组

解决:

//禁止文字选中
text{
    user-select:none;
}
//禁止图片选中
img{
    pointer-events: none
}

3.较低的ios系统下给图片添加点击事件不触发

解决:

img {
    cursor: pointer;
}

4.ios系统下图片、input点击后会出现高亮

解决:

img,input {
    -webkit-tap-highlight-color: transparent;
}

5.ios滚动时卡顿

给元素设置overflow-y:scorll属性时,在部分ios系统下拖动时会出现卡顿,滑动时感觉特别木讷。

解决:

.box {
    -webkit-overflow-scrolling: touch;

6.ios下输入框光标高度太高

内容垂直居中我习惯使用line-height属性,只要设置的跟height一样高内容就会垂直居中,但是在ios下光标的高度也会跟height一样高。

解决:

//使用padding将父元素撑开
input{
  padding-top:xxxpx;
  padding-bottom:xxxpx;
}

7.ios时间转换异常

yyyy-MM-dd HH:mm:ss格式的时间在ios下无法转换,需要改为yyyy/MM/dd HH:mm:ss格式

解决:

t = t.replace(/-/g, "/")

8.部分安卓机input得焦时输入框被键盘覆盖

解决:

document.getElementById(id).onfocus = function () {
    scrollView()
}
function scrollView(id) {
  const u = navigator.userAgent
  const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1;
  if (isAndroid) {
    setTimeout(function() {
      document.getElementById(id).scrollIntoViewIfNeeded();
      document.getElementById(id).scrollIntoView();
    }, 100);
  }
}

9.ios或者部分安卓机型video无法自动播放

自动播放音视频大多数浏览器都禁止了,常用的方法是用户触摸到屏幕时就触发播放事件。在微信环境下可以通过监听WeixinJSBridgeReady实现自动播放。

解决:

var video = document.getElementById('video');
var played = false;
document.addEventListener('touchstart', function () {
  if (!played) {
    video.play();
    played = true;
  }
}, false);
document.addEventListener("WeixinJSBridgeReady", function () {
  video.play();
}, false);
video.onended = function () {
  video.load();
  video.play();
}

10.用户修改微信字体大小导致网页布局错乱

解决:

//安卓禁止修改字体大小
if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
    handleFontSize();
} else {
    if (document.addEventListener) {
        document.addEventListener("WeixinJSBridgeReady", handleFontSize, false);
    } else if (document.attachEvent) {
        document.attachEvent("WeixinJSBridgeReady", handleFontSize);
        document.attachEvent("onWeixinJSBridgeReady", handleFontSize);
    }
}
function handleFontSize() {
    WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });
    WeixinJSBridge.on('menu:setfont', function () {
        WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });
    });
}

//ios
body {
  /* IOS禁止微信调整字体大小 */
  -webkit-text-size-adjust: 100% !important;
  text-size-adjust: 100% !important;
  -moz-text-size-adjust: 100% !important;
}

11.微信浏览器input失焦后顶起的页面没有恢复

input失焦后稍微滑动一下页面,被顶起的页面就会回归正常。

解决:

document.getElementsByTagName("input").onblur = function () {
    scrollHtml()
}
document.getElementsByTagName("select").onchange = function () {
    scrollHtml()
}
function scrollHtml() {
    let currentPosition
    const timer = setInterval(function () {
        currentPosition = document.documentElement.scrollTop || document.body.scrollTop
        currentPosition -= 1
        window.scrollTo(0, currentPosition)
        currentPosition += 1
        window.scrollTo(0, currentPosition)
        clearInterval(timer)
    }, 1)
}

12.页面后退时,上一个页面被缓存

这个问题常见于多页面应用,跳转页面后再返回,返回后页面并不会刷新,导致用户看到的数据跟真实的数据对不上。

解决:

//后退时强制刷新
window.onpageshow = function (event) {
    if (window.performance && window.performance.navigation.type == 2) {
        window.location.reload()
    }
};

13.vueRouter hash模式路由微信授权参数问题

此问题通常出现在后端做微信授权,成功后直接将用户openid返回给前端的回调地址,会被解析为类似的格式https:xxxx.com?openid=xxx#index,参数被拼接在中间的位置,导致前端vue取不到值。

解决:

// 在全局路由守卫里判断url格式,然后跳转到拼接后的正确url
router.beforeEach((to, from, next) => {
  const href = window.location.href
  if(href.indexOf('/?openid') > -1 ){
    const urlArr = href.split('/?')
    const leftUrl = urlArr[0] + '/#/'
    const rightUrlArr = urlArr[1].split('#/')
    const queryObj = {}
    rightUrlArr[0]
      .split('&')
      .map((item) => {
        const splitStr = item.split('=')
        return {
          key: splitStr[0],
          value: splitStr[1],
        }
      })
      .forEach((item) => {
        queryObj[item.key] = item.value
      })
      location.href = `${leftUrl}${rightUrlArr[1]}?${qs.stringify(queryObj)}`
  }else{
    next()
  }
})

14.小程序内轮播图开启自动轮播部分机型卡顿

部分机型,或者手机放置一会再打开会疯狂触发 小程序swiperchange 事件,

解决:

change(e) {
  let { current, source } = e.detail
  if (source === 'autoplay' || source === 'touch') {
    this.activitIndex = current;
  }
}

15.滚动穿透问题

页面内有个弹框,当我们滚动弹框是,背后的页面也会跟着滚动。

解决:

方案1:适用于弹框里的内容不需要滚动,优点:代码简单

document.getElementById(id).addEventListener('touchmove', function(e) {
  e.preventDefault();
}, false)

方案2:适用所有方式,比较麻烦:当触发弹框时获取到当前的滚动高度给body设置属性{overflow:hidden;position:fixed;top:当前滚动的高度},关闭弹框时移除掉。

let scrollT = null;
let LastScrollT = 0;
window.onscroll = function(e) {
  scrollT = getScrollOffset().y;
}
function getScrollOffset() {
  if (window.pageXOffset) {
    return {
      x: window.pageXOffset,
      y: window.pageYOffset
    }
  } else {
    return {
      x: document.body.scrollLeft || document.documentElement.scrollLeft,
      y: document.body.scrollTop || document.documentElement.scrollTop
    }
  }
};
function show() {
  layer.style.display = 'block';
  document.body.style.overflow = 'hidden';
  document.body.style.position = 'fixed';
  document.body.style.top = -scrollT + 'px';
  LastScrollT = scrollT;
}
function hide() {
  document.body.style.overflow = 'auto';
  document.body.style.position = 'static';
  if (window.pageXOffset) {
    window.pageYOffset = LastScrollT;
  } else {
    document.body.scrollTop = LastScrollT;
    document.documentElement.scrollTop = LastScrollT;
  }
}

16.多层级访问对象属性,其中某个key不存在时报错

业务代码中经常会出现这种多层级对象 var o = { info: { name: "x" } } ,访问 name 时需要写成 o.info.name 。如果 info 不存在就会报错。通常需要这么判断 o.info && o.info.name , 而 es11 新增了 ? 链式判断运算符 可以避免报错产生。

解决:

var o = {}
var name = o?.info?.name  //不报错,不存在时返回undefined

结语

如果你觉得此文对你有一丁点帮助,可以帮忙点个赞,鼓励一下作者。